Android--多线程之AsyncTask

简介:

前言

  本片博客将介绍AsyncTask的使用,之前有介绍过线程和进程。而在AsyncTask中,运行在用户界面中,执行异步操作,并且把执行结果发布在UI线程上,且也不需要处理线程和Handler。在本篇博客里,将会讲解到AsyncTask的基本介绍,以及如何使用,最后会以一个简单的Demo讲解AsyncTask的使用。

 

AsyncTask

  AsyncTask,异步任务,可以简单进行异步操作,并把执行结果发布到UI主线程。AsyncTask是一个抽象类,它的内部其实也是结合了Thread和Handler来实现异步线程操作,但是它形成了一个通用线程框架,更清晰简单。AsyncTask应该被用于比较简短的操作(最多几秒钟)。如果需要保持长时间运行的线程,可以使用ThreadPooExecutor或者FutureTask,关于这两个类的内容,以后再介绍,本片博客主要介绍AsyncTask。

  AsyncTask被定义为一个操作,运行在一个后台线程中,其结果被发布在UI线程上。它的异步工作的参数与返回值被泛型的三个参数指定:Params、Progress、Result。AsyncTask将经历4个步骤:onPreExecute、doInBackground、onProgressUpdate、onPostExecute。下面详细讲解这三个参数与四个步骤:

  三个泛型参数:

  • Params:被发送到执行任务的参数类型。
  • Progress:进度的类型,发送后台的计算进度到UI线程类型。
  • Result:异步任务的返回结果类型。

  一个异步任务将经历四个阶段:

  • onPreExecute():执行在UI线程上调用执行任务之前,一般用于设置任务。
  • doInBackground(Params...):主要是用来执行异步任务的耗时操作,可以在这个方法中通过publishProgress()方法发布进度信息,并在执行完成之后,返回执行结果。
  • onProgreddUpdate(Progress...):在UI线程上接受doInBackground()传递过来的进度信息,并在UI线程上展示进度信息,它执行的时机是不确定的。
  • onPostExecute(Result):在UI线程上操作doInBackground()执行的返回值。

  上面介绍的四个步骤的示意图:

AsyncTask取消任务

  在程序的任何位置,都可以通过cancel(boolean)方法进行取消任务,当取消任务之后,会改变isCancelled()的返回值,使其返回true。之后会调用onCancelled(Object)方法,替代onPostExecute()得到doInBackground()的返回结果。在运行中,可以经常通过isCancelled()方法查看任务是否被取消。

 

AsyncTask的使用规则

  使用AsyncTask必须遵循以下规则:

  • AsyncTask必须声明在UI线程上。
  • AsyncTask必须在UI线程上实例化。
  • 必须通过execute()方法执行任务。
  • 不可以直接调用onPreExecute()、onPostExecute(Resut)、doInBackground(Params...)、onProgressUpdate(Progress...)方法。
  • 可以设置任务只执行一次,如果企图再次执行会报错。

示例

  一个简单的示例,通过AsyncTask下载一个网络上的图片,下载的时候展示一个等待框,并显示在一个ImageView中。

  实现代码:

复制代码
 1 package com.bgxt.datatimepickerdemo;
 2 
 3 import org.apache.http.HttpEntity;
 4 import org.apache.http.HttpResponse;
 5 import org.apache.http.client.HttpClient;
 6 import org.apache.http.client.methods.HttpGet;
 7 import org.apache.http.impl.client.DefaultHttpClient;
 8 import org.apache.http.util.EntityUtils;
 9 
10 import android.app.Activity;
11 import android.app.ProgressDialog;
12 import android.graphics.Bitmap;
13 import android.graphics.BitmapFactory;
14 import android.os.AsyncTask;
15 import android.os.Bundle;
16 import android.view.View;
17 import android.widget.Button;
18 import android.widget.ImageView;
19 
20 public class AsyncTaskActivity1 extends Activity {
21     private Button btnDown;
22     private ImageView ivImage;
23     private static String image_path = "http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg";
24     private ProgressDialog dialog;
25 
26     @Override
27     protected void onCreate(Bundle savedInstanceState) {
28         // TODO Auto-generated method stub
29         super.onCreate(savedInstanceState);
30         setContentView(R.layout.asynctask_activity);
31 
32         btnDown = (Button) findViewById(R.id.btnDown);
33         ivImage = (ImageView) findViewById(R.id.ivSinaImage);
34         
35         // 声明一个等待框以提示用户等待
36         dialog=new ProgressDialog(this);
37         dialog.setTitle("提示信息");
38         dialog.setMessage("正在下载,请稍后...");
39         
40         btnDown.setOnClickListener(new View.OnClickListener() {
41 
42             @Override
43             public void onClick(View v) {
44                 // 执行一个异步任务,并把图片地址以参数的形式传递进去
45                 new MyTask().execute(image_path);
46             }
47         });
48     }
49 
50     // 以String类型的参数,Void表示没有进度信息,Bitmap表示异步任务返回一个位图
51     public class MyTask extends AsyncTask<String, Void, Bitmap> {
52         // 表示任务执行之前的操作
53         @Override
54         protected void onPreExecute() {
55             super.onPreExecute();
56             //显示等待框
57             dialog.show();
58         }
59 
60         //主要是完成耗时操作
61         @Override
62         protected Bitmap doInBackground(String... params) {
63             HttpClient httpClient=new DefaultHttpClient();
64             HttpGet httpGet=new HttpGet(params[0]);
65             Bitmap bitmap=null;
66             try {
67                 //从网络上下载图片
68                 HttpResponse httpResponse =httpClient.execute(httpGet);
69                 if(httpResponse.getStatusLine().getStatusCode()==200){
70                     HttpEntity httpEntity = httpResponse.getEntity();
71                     byte[] data=EntityUtils.toByteArray(httpEntity);
72                     bitmap=BitmapFactory.decodeByteArray(data, 0, data.length);                    
73                 }
74             } catch (Exception e) {
75                 e.printStackTrace();
76             }
77             return bitmap;
78         }
79         
80         //完成更新UI操作
81         @Override
82         protected void onPostExecute(Bitmap result) {
83             // TODO Auto-generated method stub
84             super.onPostExecute(result);
85             //设置ImageView的显示图片
86             ivImage.setImageBitmap(result);
87             // 销毁等待框
88             dialog.dismiss();
89         }
90 
91     }
92 }
复制代码

  效果展示:

  

  上面的Demo并没有用到进度的信息,下面再提供一个完整的AsyncTask的Demo,同样是下载一个图片,并且展示到一个ImageView中,但是这里在下载的过程中增加一个进度条对话框,用于展示下载的进度。

  实现代码:

复制代码
  1 package com.bgxt.datatimepickerdemo;
  2 
  3 import java.io.ByteArrayOutputStream;
  4 import java.io.InputStream;
  5 
  6 import org.apache.http.HttpResponse;
  7 import org.apache.http.client.HttpClient;
  8 import org.apache.http.client.methods.HttpGet;
  9 import org.apache.http.impl.client.DefaultHttpClient;
 10 
 11 import android.app.Activity;
 12 import android.app.ProgressDialog;
 13 import android.graphics.Bitmap;
 14 import android.graphics.BitmapFactory;
 15 import android.os.AsyncTask;
 16 import android.os.Bundle;
 17 import android.view.View;
 18 import android.widget.Button;
 19 import android.widget.ImageView;
 20 
 21 public class AsyncTaskActivity2 extends Activity {
 22     private Button btnDown;
 23     private ImageView ivImage;
 24     private static String image_path = "http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg";
 25     private ProgressDialog dialog;
 26 
 27     @Override
 28     protected void onCreate(Bundle savedInstanceState) {
 29         super.onCreate(savedInstanceState);
 30         setContentView(R.layout.asynctask_activity);
 31         btnDown = (Button) findViewById(R.id.btnDown);
 32         ivImage = (ImageView) findViewById(R.id.ivSinaImage);
 33 
 34         dialog = new ProgressDialog(this);
 35         dialog.setTitle("提示");
 36         dialog.setMessage("正在下载,请稍后...");
 37         dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
 38         dialog.setCancelable(false);
 39 
 40         btnDown.setOnClickListener(new View.OnClickListener() {
 41 
 42             @Override
 43             public void onClick(View v) {
 44                 //  执行异步任务
 45                 new MyTask().execute(image_path);
 46             }
 47         });
 48     }
 49 
 50     public class MyTask extends AsyncTask<String, Integer, Bitmap> {
 51         @Override
 52         protected void onPreExecute() {
 53             super.onPreExecute();
 54             dialog.show();
 55         }
 56 
 57         @Override
 58         protected void onProgressUpdate(Integer... values) {
 59             super.onProgressUpdate(values);
 60             // 设置进度对话框的进度值
 61             dialog.setProgress(values[0]);
 62         }
 63 
 64         @Override
 65         protected void onPostExecute(Bitmap result) {
 66             super.onPostExecute(result);
 67             dialog.dismiss();
 68             ivImage.setImageBitmap(result);
 69         }
 70 
 71         @Override
 72         protected Bitmap doInBackground(String... params) {
 73             Bitmap bitmap = null;
 74             ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
 75             InputStream inputStream = null;
 76             try {
 77                 HttpClient httpClient = new DefaultHttpClient();
 78                 HttpGet httpGet = new HttpGet(params[0]);
 79                 HttpResponse httpResponse = httpClient.execute(httpGet);
 80                 if (httpResponse.getStatusLine().getStatusCode() == 200) {
 81                     inputStream = httpResponse.getEntity().getContent();
 82                     long file_length = httpResponse.getEntity()
 83                             .getContentLength();
 84                     int len = 0;
 85                     byte[] data = new byte[1024];
 86                     int total_length = 0;
 87                     // 以字节的方式读取图片数据
 88                     while ((len = inputStream.read(data)) != -1) {
 89                         total_length += len;
 90                         // 计算进度
 91                         int values = (int) ((total_length / (float) file_length) * 100);
 92                         // 发布进度信息
 93                         publishProgress(values);
 94                         outputStream.write(data, 0, len);
 95                     }
 96                     byte[] result=outputStream.toByteArray();
 97                     bitmap=BitmapFactory.decodeByteArray(result, 0, result.length);
 98                 }
 99             } catch (Exception e) {
100                 e.printStackTrace();
101             } finally {
102                 try {
103                     if (inputStream != null) {
104                         inputStream.close();
105                     }
106                 } catch (Exception e2) {
107                 }
108             }
109             return bitmap;
110         }
111     }
112 }
复制代码

  实现效果:



本文转自承香墨影博客园博客,原文链接:http://www.cnblogs.com/plokmju/p/android_AsyncTask.html,如需转载请自行联系原作者


相关文章
|
21天前
|
Java Android开发
Android面试题经典之Glide取消加载以及线程池优化
Glide通过生命周期管理在`onStop`时暂停请求,`onDestroy`时取消请求,减少资源浪费。在`EngineJob`和`DecodeJob`中使用`cancel`方法标记任务并中断数据获取。当网络请求被取消时,`HttpUrlFetcher`的`cancel`方法设置标志,之后的数据获取会返回`null`,中断加载流程。Glide还使用定制的线程池,如AnimationExecutor、diskCacheExecutor、sourceExecutor和newUnlimitedSourceExecutor,其中某些禁止网络访问,并根据CPU核心数动态调整线程数。
41 2
|
22天前
|
安全 Java 数据处理
Android多线程编程实践与优化技巧
Android多线程编程实践与优化技巧
|
25天前
|
安全 Java 数据处理
Android多线程编程实践与优化技巧
Android多线程编程实践与优化技巧
|
1月前
|
Android开发
40. 【Android教程】AsyncTask:异步任务
40. 【Android教程】AsyncTask:异步任务
45 2
|
1月前
|
存储 Java 调度
Android面试题之Kotlin协程到底是什么?它是线程吗?
本文探讨了协程与线程的区别,指出协程并非线程,而是轻量级的线程替代。协程轻量体现在它们共享调用栈,内存占用少,仅需几个KB。协程切换发生在用户态,避免了昂贵的内核态切换。在Kotlin中,协程通过Continuation对象实现上下文保存,允许高效并发执行,而不会像线程那样消耗大量资源。通过`runBlocking`和`launch`示例展示了协程的非阻塞挂起特性。总结来说,协程的轻量主要源于内存占用少、切换开销低和高并发能力。
20 0
|
2月前
|
Java 测试技术 开发工具
Android 笔记:AndroidTrain , Lint , build(1),只需一篇文章吃透Android多线程技术
Android 笔记:AndroidTrain , Lint , build(1),只需一篇文章吃透Android多线程技术
|
1月前
|
Java Linux 数据库
59. 【Android教程】多线程
59. 【Android教程】多线程
21 0
|
2月前
|
Android开发 Kotlin API
Android插件化探索与发现,kotlin协程切换线程
Android插件化探索与发现,kotlin协程切换线程
|
2月前
|
Android开发
Android中的多线程及AsyncTask的引入,最终入职阿里
Android中的多线程及AsyncTask的引入,最终入职阿里
|
算法 Java Android开发
Android模拟多线程下载
Android模拟多线程下载
66 0