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,地址是
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();
}
}