1. 程式人生 > >Android多執行緒之AsyncTask

Android多執行緒之AsyncTask

  對Android開發者來說,如何處理多執行緒問題是無法繞過的問題。每個Android開發者或多或少都遇到過ANR(Applicatin Not Responding)異常,Android預設當UI執行緒阻塞超過20s時將會引發ANR異常。因此在處理耗時操作時應當將其放入新執行緒中,但是這樣將面臨一個問題,如何在新執行緒中更新UI元件呢?
  Android提供如下幾種方案:Handler、AsyncTask、Activity.runOnUiThread(Runnable)、View.post(Runnable)和View.postDelayed(Runnable,long)。其中Handler功能最強大,處理最靈活,實際上AsyncTask正是對Handler的封裝,而後三種方式則略顯繁瑣。AsyncTask是Android開發非常常用的處理多執行緒問題的工具,使用起來也簡單方便,適用於簡單的非同步處理。
  
  AsyncTask是一個抽象類,通常用於被繼承,需要制定三個泛型引數。Params,啟動任務執行時的輸入引數的型別;Progress,後臺執行任務時進度值的型別;Result,後臺執行任務返回結果的型別。通常需要實現AsyncTask的如下方法:doInBackgroud(Params…)完成後臺執行的任務,只有這個方法在新執行緒中執行。onProgressUpdate(Progress… values),當在doInBackgroud()方法中呼叫publishProgress(Progress… values)時將觸發該方法,用於顯示任務執行的進度;onPreExecute()用於在執行後臺任務前完成一些初始化的工作;onPostExecute(Result result):在完成後臺任務後,doInBackgroud()方法會把返回值傳給該方法,該方法一般用於更新UI。     
  使用AsyncTask時一般遵循如下規則:必須在UI執行緒中建立AsyncTask的例項並呼叫execute()方法;AsyncTask的方法由Android自動呼叫,執行順序是onPreExecute()、doInBackgroud()、onProgressUpdate()和onPostExecute();每個AnyncTask只能被執行一次,多次呼叫將引發異常。
     


  筆者使用AsyncTask實現了一個下載圖片的示例app。原始碼及app截圖說明已上傳至我的githubhttps://github.com/WenZhuang/AndroidDemos。AndroidDemos是我在github新建的一個倉庫,以後會上傳更多的Android示例程式程式碼。
  其中,ImageTask擴充套件了AsyncTask,我單獨把ImageTask的原始碼上傳至AndroidUtils倉庫https://github.com/WenZhuang/AndroidUtils/blob/master/ImageTask.java。我的AndroidUtils倉庫用於存放有用的Android工具類,ImageTask可作為下載圖片的工具類。另外歡迎大家關注我的github,地址是
https://github.com/WenZhuang

  
  ImageTask的原始碼如下所示。使用ImageTask時,先要傳入一個Context物件和一個ImageView物件作為ImageTask建構函式的引數,並且在呼叫execute()時需要傳入圖片的URL地址。在onPreExecute()方法中,實現了對進度條的設定和顯示。因為沒有使用水平進度條來顯示進度,因此沒有重寫onProgressUpdate()方法。在doInBackground(String…)方法中,使用了HttpClient訪問網路,關於HttpClient的使用方法請見我的博文。使用BitmapFactory的decodeStream(InputStream)方法將網路輸入流轉化成Bitmap物件。在onPostExecute(Bitmap)中實現了將圖片裝載入ImageView,並且讓進度條消失。

import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import java.io.IOException;

/**
 * Created by JohnVenn on 2015/12/12.
 */
class ImageTask extends AsyncTask<String,Void,Bitmap> {

    private ProgressDialog dialog;
    private Context context;
    private ImageView imageView;
    ImageTask(Context context,ImageView imageView) {
        this.context = context;
        this.imageView = imageView;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        Bitmap bitmap = null;
        HttpClient httpClient = new DefaultHttpClient();
        HttpGet httpRequest = new HttpGet(params[0]);
        try {
            HttpResponse httpResponse = httpClient.execute(httpRequest);
            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                bitmap = BitmapFactory.decodeStream(httpResponse.getEntity().getContent());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        dialog = new ProgressDialog(context);
        dialog.setTitle("圖片正在下載");
        dialog.setMessage("正在為您玩命下載中......");
        dialog.setCancelable(false);
        dialog.show();
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);
        imageView.setImageBitmap(bitmap);
        dialog.dismiss();
    }
}