AsyncTask使用简介


http://blog.csdn.net/qianfu111/article/details/10200105


在Android中实现异步任务机制有两种方式,Handler和AsyncTask。

Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制。

为了简化操作,Android1.5提供了工具类android.os.AsyncTask,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。AsyncTask的内部实现是一个线程池,每个后台任务会提交到线程池中的线程执行,然后使用Thread+Handler的方式调用回调函数。


定义: public abstract class AsyncTask<Params, Progress, Result>

三种泛型类型分别代表“启动任务执行的输入参数”、“后台任务执行的进度”、“后台计算结果的类型”。在特定场合下,并不是所有类型都被使用,如果没有被使用,可以用java.lang.Void类型代替。


AsyncTask抽象出后台线程运行的五个状态,分别是:1、准备运行,2、正在后台运行,3、进度更新,4、完成后台任务,5、取消任务,对于这五个阶段,AsyncTask提供了五个回调函数:

1、准备运行:onPreExecute(),该回调函数在任务被执行之后立即由UI线程调用。这个步骤通常用来建立任务,在用户接口(UI)上显示进度条。

2、正在后台运行:doInBackground(Params...),该回调函数由后台线程在onPreExecute()方法执行结束后立即调用。通常在这里执行耗时的后台计算。计算的结果必须由该函数返回,并被传递到onPostExecute()中。在该函数内也可以使用publishProgress(Progress...)来发布一个或多个进度单位(unitsof progress)。这些值将会在onProgressUpdate(Progress...)中被发布到UI线程。

3. 进度更新:onProgressUpdate(Progress...),该函数由UI线程在publishProgress(Progress...)方法调用完后被调用。一般用于动态地显示一个进度条。

4. 完成后台任务:onPostExecute(Result),当后台计算结束后调用。后台计算的结果会被作为参数传递给这一函数。

5、取消任务:onCancelled (),在调用AsyncTask的cancel()方法时调用。


在使用的时候,有几点需要格外注意:

1.异步任务的实例必须在UI线程中创建。

2.execute(Params... params)方法必须在UI线程中调用。

3.不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法。

4.不能在doInBackground(Params... params)中更改UI组件的信息。

5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。


内存可观测性:

AsyncTask保证所有回调是同步的,下面的操作没有显式进行同步,但也是安全的。

1、在构造函数或者onPreExecute()中设置成员字段,在doInBackground(Params...)中引用。

2、在doInBackground(Params...)中设置成员字段,在onProgressUpdate(Progress...)和onPostExecute(Result)中引用。


注意事项:

1、当有需要大量线程执行任务时,一定要创建线程池

2、对于想要立即开始执行的异步任务,要么直接使用Thread,要么单独创建线程池提供给AsyncTask。默认的AsyncTask不一定会立即执行你的任务,除非你提供给他一个单独的线程池。如果不与主线程交互,直接创建一个Thread就可以了,虽然创建线程开销比较大,但如果这不是批量操作就没有问题。


下面是一个简单Demo:

MainActivity类的代码:

[java]  view plain copy
  1. package com.example.mygeneralutil;  
  2.   
  3. import java.net.URI;  
  4.   
  5. import org.apache.http.HttpResponse;  
  6. import org.apache.http.client.HttpClient;  
  7. import org.apache.http.client.methods.HttpGet;  
  8. import org.apache.http.impl.client.DefaultHttpClient;  
  9.   
  10. import android.os.AsyncTask;  
  11. import android.os.Bundle;  
  12. import android.app.Activity;  
  13. import android.graphics.Bitmap;  
  14. import android.graphics.BitmapFactory;  
  15. import android.util.Log;  
  16. import android.view.Menu;  
  17. import android.view.View;  
  18. import android.view.View.OnClickListener;  
  19. import android.widget.Button;  
  20. import android.widget.ImageView;  
  21. import android.widget.ProgressBar;  
  22. import android.widget.Toast;  
  23.   
  24. public class MainActivity extends Activity {  
  25.   
  26.     private Button mDownloadBtn;  
  27.     private Button mCancelBtn;  
  28.     private ImageView mImage1;  
  29.     private ImageView mImage2;  
  30.     private ProgressBar mProgress1;  
  31.     private ProgressBar mProgress2;  
  32.     private GetLogoFromInternet mTask;  
  33.     private String TAG = "GetLogoFromInternet";  
  34.   
  35.     @Override  
  36.     protected void onCreate(Bundle savedInstanceState) {  
  37.         super.onCreate(savedInstanceState);  
  38.         setContentView(R.layout.asynctask_activity);  
  39.         initComponent();  
  40.     }  
  41.   
  42.     private void initComponent() {  
  43.   
  44.         mDownloadBtn = (Button) findViewById(R.id.button1);  
  45.         mDownloadBtn.setOnClickListener(new OnClickListener() {  
  46.   
  47.             @Override  
  48.             public void onClick(View v) {  
  49.                 mTask = new GetLogoFromInternet();  
  50.                 mTask.execute(  
  51.                         "http://d.hiphotos.baidu.com/album/w%3D2048/sign=6b4e0cbb023b5bb5bed727fe02ebd439/7dd98d1001e939016245802e7aec54e736d1965e.jpg",  
  52.                         "http://a.hiphotos.baidu.com/album/w%3D2048/sign=4a44fc70342ac65c67056173cfcab311/b8389b504fc2d562f5f6f0fde61190ef76c66c27.jpg");  
  53.   
  54.             }  
  55.         });  
  56.         mCancelBtn = (Button) findViewById(R.id.button2);  
  57.         mCancelBtn.setOnClickListener(new OnClickListener() {  
  58.   
  59.             @Override  
  60.             public void onClick(View v) {  
  61.                 // TODO Auto-generated method stub  
  62.                 mTask.cancel(true);  
  63.             }  
  64.         });  
  65.   
  66.         mImage1 = (ImageView) findViewById(R.id.imageView1);  
  67.         mImage2 = (ImageView) findViewById(R.id.imageView2);  
  68.         mProgress1 = (ProgressBar) findViewById(R.id.progressBar1);  
  69.         mProgress2 = (ProgressBar) findViewById(R.id.progressBar2);  
  70.     }  
  71.   
  72.     @Override  
  73.     public boolean onCreateOptionsMenu(Menu menu) {  
  74.         // Inflate the menu; this adds items to the action bar if it is present.  
  75.         getMenuInflater().inflate(R.menu.main, menu);  
  76.         return true;  
  77.     }  
  78.   
  79.     class GetLogoFromInternet extends AsyncTask<String, Integer, Bitmap> {  
  80.   
  81.         private Bitmap bitmap = null;  
  82.   
  83.         @Override  
  84.         protected void onPreExecute() {  
  85.             mImage1.setImageBitmap(null);  
  86.             mImage2.setImageBitmap(null);  
  87.             mProgress1.setProgress(0);  
  88.             mProgress2.setProgress(0);  
  89.             Log.e(TAG, "onPreExecute");  
  90.         }  
  91.   
  92.         @Override  
  93.         protected Bitmap doInBackground(String... params) {  
  94.             publishProgress(00);  
  95.   
  96.             HttpClient hc = new DefaultHttpClient();  
  97.             publishProgress(300);  
  98.             HttpGet hg = new HttpGet();  
  99.             Bitmap bitmap2 = null;  
  100.             try {  
  101.                 hg.setURI(new URI(params[0]));  
  102.                 HttpResponse response = hc.execute(hg);  
  103.                 bitmap = BitmapFactory.decodeStream(response.getEntity()  
  104.                         .getContent());  
  105.                 publishProgress(10030);  
  106.   
  107.                 hg.setURI(new URI(params[1]));  
  108.                 HttpResponse response2 = hc.execute(hg);  
  109.                 bitmap2 = BitmapFactory.decodeStream(response2.getEntity()  
  110.                         .getContent());  
  111.   
  112.             } catch (Exception e) {  
  113.                 Log.e(TAG, "" + e.getMessage());  
  114.             }  
  115.             publishProgress(100100);  
  116.             Log.e(TAG, "doInBackground");  
  117.             // mImage1.setImageBitmap(bitmap);//error  
  118.             return bitmap2;  
  119.   
  120.         }  
  121.   
  122.         @Override  
  123.         protected void onProgressUpdate(Integer... values) {  
  124.             mProgress1.setProgress(values[0]);  
  125.             mProgress2.setProgress(values[1]);  
  126.             Log.e(TAG, "onProgressUpdate");  
  127.         }  
  128.   
  129.         @Override  
  130.         protected void onPostExecute(Bitmap result) {  
  131.             if (result != null) {  
  132.                 mImage1.setImageBitmap(bitmap);  
  133.                 mImage2.setImageBitmap(result);  
  134.                 Toast.makeText(MainActivity.this,  
  135.                         "get image from network successful", Toast.LENGTH_SHORT)  
  136.                         .show();  
  137.             } else {  
  138.                 Toast.makeText(MainActivity.this,  
  139.                         "get image from network error", Toast.LENGTH_SHORT)  
  140.                         .show();  
  141.             }  
  142.             Log.e(TAG, "onPostExecute");  
  143.         }  
  144.   
  145.         @Override  
  146.         protected void onCancelled() {  
  147.             mProgress1.setProgress(0);  
  148.             mProgress2.setProgress(0);  
  149.             Log.e(TAG, "onCancelled");  
  150.         }  
  151.   
  152.     }  
  153. }  

相应布局文件:

[java]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="#ffffff"  
  6.     android:orientation="vertical" >  
  7.   
  8.     <ScrollView  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="match_parent"  
  11.         android:padding="10dp" >  
  12.   
  13.         <LinearLayout  
  14.             android:layout_width="match_parent"  
  15.             android:layout_height="wrap_content"  
  16.             android:gravity="center"  
  17.             android:orientation="vertical" >  
  18.   
  19.             <ProgressBar  
  20.                 android:id="@+id/progressBar1"  
  21.                 style="?android:attr/progressBarStyleHorizontal"  
  22.                 android:layout_width="match_parent"  
  23.                 android:layout_height="wrap_content" />  
  24.   
  25.             <ImageView  
  26.                 android:id="@+id/imageView1"  
  27.                 android:layout_width="150dp"  
  28.                 android:layout_height="150dp" />  
  29.   
  30.             <ProgressBar  
  31.                 android:id="@+id/progressBar2"  
  32.                 style="?android:attr/progressBarStyleHorizontal"  
  33.                 android:layout_width="match_parent"  
  34.                 android:layout_height="wrap_content" />  
  35.   
  36.             <ImageView  
  37.                 android:id="@+id/imageView2"  
  38.                 android:layout_width="150dp"  
  39.                 android:layout_height="150dp" />  
  40.   
  41.             <Button  
  42.                 android:id="@+id/button1"  
  43.                 android:layout_width="match_parent"  
  44.                 android:layout_height="wrap_content"  
  45.                 android:text="download image" />  
  46.   
  47.             <Button  
  48.                 android:id="@+id/button2"  
  49.                 android:layout_width="match_parent"  
  50.                 android:layout_height="wrap_content"  
  51.                 android:text="cancel download image" />  
  52.         </LinearLayout>  
  53.     </ScrollView>  
  54.   
  55. </LinearLayout>  


补充AsyncTask执行流程:

当我们调用execute(Params... params)方法后,execute方法会调用onPreExecute()方法,然后由ThreadPoolExecutor实例sExecutor执行一个FutureTask任务,这个过程中doInBackground(Params... params)将被调用,如果被开发者覆写的doInBackground(Params... params)方法中调用了publishProgress(Progress... values)方法,则通过InternalHandler实例sHandler发送一条MESSAGE_POST_PROGRESS消息,更新进度,sHandler处理消息时onProgressUpdate(Progress... values)方法将被调用;如果遇到异常,则发送一条MESSAGE_POST_CANCEL的消息,取消任务,sHandler处理消息时onCancelled()方法将被调用;如果执行成功,则发送一条MESSAGE_POST_RESULT的消息,显示结果,sHandler处理消息时onPostExecute(Result result)方法被调用。

如果需要google源码的详细说明,看下面的参考文献,写的非常好。


参考文献:
详解Android中AsyncTask的使用: http://blog.csdn.net/liuhe688/article/details/6532519
Android实战技巧:深入解析AsyncTask: http://blog.csdn.net/hitlion2008/article/details/7983449

你可能感兴趣的:(AsyncTas)