1. 程式人生 > >Android中非同步任務機制AsyncTask的理解

Android中非同步任務機制AsyncTask的理解

在Android中實現非同步任務機制有兩種方式,Handler和AsyncTask。

Handler模式需要為每一個任務建立一個新的執行緒,任務完成後通過Handler例項向UI執行緒傳送訊息,完成介面的更新,這種方式對於整個過程的控制比較精細,但也是有缺點的,例如程式碼相對臃腫,在多個任務同時執行時,不易對執行緒進行精確的控制。關於Handler的相關知識,前面也有所介紹,不清楚的朋友們可以參照一下。

為了簡化操作,Android1.5提供了工具類android.os.AsyncTask,它使建立非同步任務變得更加簡單,不再需要編寫任務執行緒和Handler例項即可完成相同的任務。

先來看看AsyncTask的定義:

  1. publicabstractclass AsyncTask<Params, Progress, Result> {  

三種泛型型別分別代表“啟動任務執行的輸入引數”、“後臺任務執行的進度”、“後臺計算結果的型別”。在特定場合下,並不是所有型別都被使用,如果沒有被使用,可以用java.lang.Void型別代替。

一個非同步任務的執行一般包括以下幾個步驟:

1.execute(Params... params),執行一個非同步任務,需要我們在程式碼中呼叫此方法,觸發非同步任務的執行。

2.onPreExecute()

,在execute(Params... params)被呼叫後立即執行,一般用來在執行後臺任務前對UI做一些標記。

3.doInBackground(Params... params),在onPreExecute()完成後立即執行,用於執行較為費時的操作,此方法將接收輸入引數和返回計算結果。在執行過程中可以呼叫publishProgress(Progress... values)來更新進度資訊。

4.onProgressUpdate(Progress... values),在呼叫publishProgress(Progress... values)時,此方法被執行,直接將進度資訊更新到UI元件上。

5.onPostExecute(Result result),當後臺操作結束時,此方法將會被呼叫,計算結果將做為引數傳遞到此方法中,直接將結果顯示到UI元件上。

在使用的時候,有幾點需要格外注意:

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執行非同步任務操作,我們先建立一個專案,結構如下:

結構相對簡單一些,讓我們先看看MainActivity.java的程式碼:

  1. package com.scott.async;  
  2. import java.io.ByteArrayOutputStream;  
  3. import java.io.InputStream;  
  4. import org.apache.http.HttpEntity;  
  5. import org.apache.http.HttpResponse;  
  6. import org.apache.http.HttpStatus;  
  7. import org.apache.http.client.HttpClient;  
  8. import org.apache.http.client.methods.HttpGet;  
  9. import org.apache.http.impl.client.DefaultHttpClient;  
  10. import android.app.Activity;  
  11. import android.os.AsyncTask;  
  12. import android.os.Bundle;  
  13. import android.util.Log;  
  14. import android.view.View;  
  15. import android.widget.Button;  
  16. import android.widget.ProgressBar;  
  17. import android.widget.TextView;  
  18. publicclass MainActivity extends Activity {  
  19.     privatestaticfinal String TAG = "ASYNC_TASK";  
  20.     private Button execute;  
  21.     private Button cancel;  
  22.     private ProgressBar progressBar;  
  23.     private TextView textView;  
  24.     private MyTask mTask;  
  25.     @Override
  26.     publicvoid onCreate(Bundle savedInstanceState) {  
  27.         super.onCreate(savedInstanceState);  
  28.         setContentView(R.layout.main);  
  29.         execute = (Button) findViewById(R.id.execute);  
  30.         execute.setOnClickListener(new View.OnClickListener() {  
  31.             @Override
  32.             publicvoid onClick(View v) {  
  33.                 //注意每次需new一個例項,新建的任務只能執行一次,否則會出現異常
  34.                 mTask = new MyTask();  
  35.                 mTask.execute("http://www.baidu.com");  
  36.                 execute.setEnabled(false);  
  37.                 cancel.setEnabled(true);  
  38.             }  
  39.         });  
  40.         cancel = (Button) findViewById(R.id.cancel);  
  41.         cancel.setOnClickListener(new View.OnClickListener() {  
  42.             @Override
  43.             publicvoid onClick(View v) {  
  44.                 //取消一個正在執行的任務,onCancelled方法將會被呼叫
  45.                 mTask.cancel(true);  
  46.             }  
  47.         });  
  48.         progressBar = (ProgressBar) findViewById(R.id.progress_bar);  
  49.         textView = (TextView) findViewById(R.id.text_view);  
  50.     }  
  51.     privateclass MyTask extends AsyncTask<String, Integer, String> {  
  52.         //onPreExecute方法用於在執行後臺任務前做一些UI操作
  53.         @Override
  54.         protectedvoid onPreExecute() {  
  55.             Log.i(TAG, "onPreExecute() called");  
  56.             textView.setText("loading...");  
  57.         }  
  58.         //doInBackground方法內部執行後臺任務,不可在此方法內修改UI
  59.         @Override
  60.         protected String doInBackground(String... params) {  
  61.             Log.i(TAG, "doInBackground(Params... params) called");  
  62.             try {  
  63.                 HttpClient client = new DefaultHttpClient();  
  64.                 HttpGet get = new HttpGet(params[0]);  
  65.                 HttpResponse response = client.execute(get);  
  66.                 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {  
  67.                     HttpEntity entity = response.getEntity();  
  68.                     InputStream is = entity.getContent();  
  69.                     long total = entity.getContentLength();  
  70.                     ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  71.                     byte[] buf = newbyte[1024];  
  72.                     int count = 0;  
  73.                     int length = -1;  
  74.                     while ((length = is.read(buf)) != -1) {  
  75.                         baos.write(buf, 0, length);  
  76.                         count += length;  
  77.                         //呼叫publishProgress公佈進度,最後onProgressUpdate方法將被執行
  78.                         publishProgress((int) ((count / (float) total) * 100));  
  79.                         //為了演示進度,休眠500毫秒
  80.                         Thread.sleep(500);  
  81.                     }  
  82.                     returnnew String(baos.toByteArray(), "gb2312");  
  83.                 }  
  84.             } catch (Exception e) {  
  85.                 Log.e(TAG, e.getMessage());  
  86.             }  
  87.             returnnull;  
  88.         }  
  89.         //onProgressUpdate方法用於更新進度資訊
  90.         @Override
  91.         protectedvoid onProgressUpdate(Integer... progresses) {  
  92.             Log.i(TAG, "onProgressUpdate(Progress... progresses) called");  
  93.