Android多线程分析之五:使用AsyncTask异步下载图像
2017-05-22 21:31 tlnshuju 阅读(138) 评论(0) 编辑 收藏 举报Android多线程分析之五:使用AsyncTask异步下载图像
在本系列文章的第一篇《Android多线程分析之中的一个:使用Thread异步下载图像》中。曾演示了怎样使用 Thread 来完毕异步任务。
Android 为了简化在 UI 线程中完毕异步任务(毕竟 UI 线程是 app 最重要的线程)。实现了一个名为 AysncTask 的模板类。使用 AysncTask 能够在异步任务进行的同一时候,将任务进度状态反馈给 UI 线程(如让 UI 线程更新进度条)。正是由于它与 UI 线程紧密相关,使用的时候要就有一些限制。AysncTask 必须在 UI 线程中创建。并在 UI 线程中启动(通过调用其 execute() 方法)。此外,AysncTask 设计的目的是用于一些耗时较短的任务,假设是耗时较长的任务不推荐使用 AysncTask。
能够用简化记忆 “三參数。四步骤” 来学习 AysncTask。
即带有三个模板參数 <Params, Progress, Result>。四个处理步骤:onPreExecute。doInBackground,onProgressUpdate,onPostExecute。
三參数:
Params 是异步任务所需的參数类型,也即 doInBackground(Params... params) 方法的參数类型;Progress 是指进度的參数类型,也即 onProgressUpdate(Progress... values) 方法的參数类型。
Result 是指任务完毕返回的參数类型,也即 onPostExecute(Result result) 或 onCancelled(Result result) 方法的參数类型。
假设某一个參数类型没有意义或没有被用到。传递 void 就可以。
四步骤:
protected void onPreExecute():在 UI 线程中运行。在异步任务開始之前被运行,以便 UI 线程完毕一些初始化动作,如将进度条清零。
protected abstract Result doInBackground(Params... params):在后台线程中运行。这是完毕异步任务的地方,它是抽象接口。子类必须提供实现;
protected void onProgressUpdate(Progress... values):在 UI 线程中运行。在异步任务运行的过程中能够通过调用 void publishProgress(Progress... values) 方法通知 UI 线程在 onProgressUpdate 方法内更新进度状态;
protected void onPostExecute(Result result):在 UI 线程中运行,当异步任务完毕之后被运行,以便 UI 线程更新任务完毕状态。
AysncTask 支持取消异步任务,当异步任务被取消之后,上面的步骤四就不会被运行了,取而代之将运行 onCancelled(Result result),以便 UI 线程更新任务被取消之后的状态。
谨记:上面提到的这些方法都是回调函数,不须要用户手动去调用。
曾经的 AysncTask 是基于单一后台线程实现的。而从 Android 3.0 起 AysncTask 是基于 Android 的并发库(java.util.concurrent)实现的,本文中不会展开讨论其详细实现,仅仅是演示怎样使用 AysncTask。
使用演示样例:
有了前面的轮廓介绍,再来使用 AysncTask 是很easy的,以下的样例与 《使用Thread异步下载图像》中的样例很类似,仅仅只是是使用 AysncTask 来完毕异步任务罢了。
这是一个使用 AysncTask 从网络上异步下载图片并在 ImageView 中显示的的简单演示样例。由于须要訪问网络。所以要在 manifest.xml 中加入网络訪问权限:
<uses-permission android:name="android.permission.INTERNET"> </uses-permission>
布局文件很简单,一个 Button,一个 ImageView:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="10dip" > <Button android:id="@+id/LoadButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Load"> </Button> <ImageView android:id="@+id/ImageVivew" android:layout_width="match_parent" android:layout_height="400dip" android:scaleType="centerInside" android:padding="2dp"> </ImageView> </LinearLayout>
接下来看代码:
首先来看定义:图片的 url 路径,两个消息值以及一些控件:
private static final String sImageUrl = "http://fashion.qqread.com/ArtImage/20110225/0083_13.jpg"; private Button mLoadButton; private ImageView mImageView;
然后来看控件的设置:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i("UI thread", " >> onCreate()"); mImageView = (ImageView)this.findViewById(R.id.ImageVivew); mLoadButton = (Button)this.findViewById(R.id.LoadButton); mLoadButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { LoadImageTask task = new LoadImageTask(v.getContext()); task.execute(sImageUrl); } }); }
LoadImageTask 继承自 AysncTask。由这个类去完毕异步图片下载任务,并对应地更新 UI 状态。
class LoadImageTask extends AsyncTask<String, Integer, Bitmap> { private ProgressDialog mProgressBar; LoadImageTask(Context context) { mProgressBar = new ProgressDialog(context); mProgressBar.setCancelable(true); mProgressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mProgressBar.setMax(100); } @Override protected Bitmap doInBackground(String... params) { Log.i("Load thread", " >> doInBackground()"); Bitmap bitmap = null; try{ publishProgress(10); Thread.sleep(1000); InputStream in = new java.net.URL(sImageUrl).openStream(); publishProgress(60); Thread.sleep(1000); bitmap = BitmapFactory.decodeStream(in); in.close(); } catch (Exception e) { e.printStackTrace(); } publishProgress(100); return bitmap; } @Override protected void onCancelled() { super.onCancelled(); } @Override protected void onPreExecute() { mProgressBar.setProgress(0); mProgressBar.setMessage("Image downloading ... %0"); mProgressBar.show(); Log.i("UI thread", " >> onPreExecute()"); } @Override protected void onPostExecute(Bitmap result) { Log.i("UI thread", " >> onPostExecute()"); if (result != null) { mProgressBar.setMessage("Image downloading success!"); mImageView.setImageBitmap(result); } else { mProgressBar.setMessage("Image downloading failure!"); } mProgressBar.dismiss(); } @Override protected void onProgressUpdate(Integer... values) { Log.i("UI thread", " >> onProgressUpdate() %" + values[0]); mProgressBar.setMessage("Image downloading ... %" + values[0]); mProgressBar.setProgress(values[0]); } };
在 LoadImageTask 中。前面提到的四个步骤都涉及到了:
首先在任务開始之前在 onPreExecute() 方法中设置进度条的初始状态(UI线程)。然后在下载线程中运行 doInBackground() 以完毕下载任务。并在当中调用 publishProgress() 来通知 UI 线程更新进度状态;UI 线程在 onProgressUpdate() 中得知进度,并更新进度条(UI线程);最后下载任务完毕,UI 线程在 onPostExecute() 中得知下载好的图像,并更新UI显示该图像(UI线程)。