Android多线程分析之五:使用AsyncTask异步下载图像

CC 许可,转载请注明出处

在本系列文章的第一篇《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 是非常容易的,下面的例子与 《使用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线程)。

Android多线程分析之五:使用AsyncTask异步下载图像的更多相关文章

  1. Android多线程分析之一:使用Thread异步下载图像

    Android多线程分析之一:使用Thread异步下载图像 罗朝辉 (http://www.cnblogs.com/kesalin) CC 许可,转载请注明出处   打算整理一下对 Android F ...

  2. Android多线程分析之中的一个:使用Thread异步下载图像

    Android多线程分析之中的一个:使用Thread异步下载图像 罗朝辉 (http://blog.csdn.net/kesalin) CC 许可.转载请注明出处 打算整理一下对 Android Fr ...

  3. android AsyncTask异步下载并更新进度条

    AsyncTask异步下载并更新进度条    //如果不是很明白请看上篇文章的异步下载 AsyncTask<String, Integer, String> 第一个参数:String 传入 ...

  4. Android多线程分析之三:Handler,Looper的实现

    Android多线程分析之三:Handler,Looper的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多 ...

  5. Android多线程分析之四:MessageQueue的实现

    Android多线程分析之四:MessageQueue的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前面两篇文章<Androi ...

  6. Android多线程分析之二:Thread的实现

    Android多线程分析之二:Thread的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处   在前文<Android多线程分析之一 ...

  7. Android Telephony分析(七) ---- 接口扩展(异步转同步)

    本文是基于上一篇<Android Telephony分析(六) —- 接口扩展(实践篇)>来写的.上一篇介绍的接口扩展的方法需要实现两部分代码:1. 从APP至RIL,发送请求:2. 从R ...

  8. android 多线程Thread,Runnable,Handler,AsyncTask

    先看两个链接: 1.http://www.2cto.com/kf/201404/290494.html 2. 链接1: android 的多线程实际上就是java的多线程.android的UI线程又称 ...

  9. Android 核心分析 之五基本空间划分

    基本空间划分 Google给了我们一张系统架构图,在这张图上我们可以看到Android的大体框架组成.                   11.jpg (175.6 KB, 下载次数: 0) 下载附 ...

随机推荐

  1. vpython初探

    vpython 是python默认的3D模块,和python有一样的风格.与PyOpenGL相比,容易上手. vpython下载:vpython的官网(www.vpython.org).顺便说一句,官 ...

  2. runtime 运行机制2

    Mike_zh QQ:82643885 end: blogTitle 博客的标题和副标题 博客园 首页 新随笔 联系 订阅 <a id="MyLinks1_XMLLink" ...

  3. mvc理解篇

    java是面向对象的语言. mvc是一种设计模式,就像论文排版,设置好论文的框架,字体,大小,颜色等,然后把论文内容往里填.mvc的出现让代码的层次更加的清晰,业务通过数据流实现. mvc框架的优点如 ...

  4. winform初学

    一.建立winform工程项目

  5. Number()数据类型转换

    Number() 如果是 Boolean 值, 和.如果是数字值,只是简单的传入和返回.如果是 .如果是 undefined,返回NaN. 如果是字符串,遵循下列规则:    如果字符串中只包含数字( ...

  6. Android多线程机制和Handler的使用

    参考教程:iMooc关于Handler,http://www.imooc.com/learn/267 参考资料:Google提供Android文档Communicating with the UI T ...

  7. TCP头部结构

    3.2 TCP头部结构 TCP头部信息出现在每个TCP报文段中,用于指定通信的源端端口,目的端端口,管理TCP连接等,本节详细介绍TCP的头部结构,包括固定头部结构和头部选项. 3.2.1 TCP固定 ...

  8. winfrom调用FastReport模板

    '存放模板的路径 If Dir(Application.StartupPath & "\ReportsFile\HB\01\IN.frx", FileAttribute.N ...

  9. IE9控件安装方法

    打开上传页面,IE提示安装控件,点击安装   刷新网页,点击允许运行加载项,需要允许两次

  10. Extjs4.2或以上 使用自定义事件时报错问题

    最近使用了extjs 自定义事件模型,代码如下: function Person(name) { this.name = name; this.addEvents('walk'); } Ext.ext ...