9.2.4 使用 AsyncTask
不過為了更加友善我們在子線程中對 UI 進行操作,Android 還提供了另外一些好用的工 具,AsyncTask 就是其中之一。借助 AsyncTask,即使你對異步消息處理機制完全不了解, 也可以十分簡單地從子線程切換到主線程。當然,AsyncTask 背後的實作原理也是基于異步 消息處理機制的,隻是 Android 幫我們做了很好的封裝而已。
首先來看一下 AsyncTask 的基本用法,由于 AsyncTask 是一個抽象類,是以如果我們想 使用它,就必須要建立一個子類去繼承它。在繼承時我們可以為 AsyncTask 類指定三個泛型 參數,這三個參數的用途如下。
1. Params
在執行 AsyncTask 時需要傳入的參數,可用于在背景任務中使用。
2. Progress
背景任務執行時,如果需要在界面上顯示目前的進度,則使用這裡指定的泛型作為 進度機關。
3. Result
當任務執行完畢後,如果需要對結果進行傳回,則使用這裡指定的泛型作為傳回值 類型。
是以,一個最簡單的自定義 AsyncTask 就可以寫成如下方式:
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
……
}
這裡我們把 AsyncTask 的第一個泛型參數指定為 Void,表示在執行 AsyncTask 的時候不 需要傳入參數給背景任務。第二個泛型參數指定為 Integer,表示使用整型資料來作為進度顯 示機關。第三個泛型參數指定為 Boolean,則表示使用布爾型資料來回報執行結果。
當然,目前我們自定義的 DownloadTask 還是一個空任務,并不能進行任何實際的操作, 我們還需要去重寫 AsyncTask 中的幾個方法才能完成對任務的定制。經常需要去重寫的方法 有以下四個。
1. onPreExecute()
這個方法會在背景任務開始執行之前調用,用于進行一些界面上的初始化操作,比 如顯示一個進度條對話框等。
2. doInBackground(Params...)
這個方法中的所有代碼都會在子線程中運作,我們應該在這裡去處理所有的耗時任 務。任務一旦完成就可以通過 return 語句來将任務的執行結果傳回,如果 AsyncTask 的 第三個泛型參數指定的是 Void,就可以不傳回任務執行結果。注意,在這個方法中是不 可以進行 UI 操作的,如果需要更新 UI 元素,比如說回報目前任務的執行進度,可以調 用 publishProgress(Progress...)方法來完成。
3. onProgressUpdate(Progress...)
當在背景任務中調用了 publishProgress(Progress...)方法後,這個方法就會很快被調 用,方法中攜帶的參數就是在背景任務中傳遞過來的。在這個方法中可以對 UI 進行操 作,利用參數中的數值就可以對界面元素進行相應地更新。
4. onPostExecute(Result)
當背景任務執行完畢并通過 return 語句進行傳回時,這個方法就很快會被調用。返 回的資料會作為參數傳遞到此方法中,可以利用傳回的資料來進行一些 UI 操作,比如 說提醒任務執行的結果,以及關閉掉進度條對話框等。
是以,一個比較完整的自定義 AsyncTask 就可以寫成如下方式:
@Override
protected void onPreExecute() {
progressDialog.show(); // 顯示進度對話框
@Override
protected Boolean doInBackground(Void... params) {
try {
while (true) {
int downloadPercent = doDownload(); // 這是一個虛構的方法
publishProgress(downloadPercent);
if (downloadPercent >= 100) {
break;
} catch (Exception e) {
return false;
return true;
protected void onProgressUpdate(Integer... values) {
// 在這裡更新下載下傳進度
progressDialog.setMessage("Downloaded " + values[0] + "%");
protected void onPostExecute(Boolean result) {
progressDialog.dismiss(); // 關閉進度對話框
// 在這裡提示下載下傳結果
if (result) {
Toast.makeText(context, "Download succeeded", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, " Download failed", Toast.LENGTH_SHORT).show();
在這個 DownloadTask 中,我們在 doInBackground()方法裡去執行具體的下載下傳任務。這個方法裡的代碼都是在子線程中運作的,因而不會影響到主線程的運作。注意這裡虛構了一個 doDownload()方法,這個方法用于計算目前的下載下傳進度并傳回,我們假設這個方法已經存在
了 。 在 得 到 了 當 前 的 下 載 進 度 後 , 下 面 就 該 考 慮 如 何 把 它 顯 示 到 界 面 上 了 , 由 于 doInBackground()方法是在子線程中運作的,在這裡肯定不能進行 UI 操作,是以我們可以調
用 publishProgress()方法并将目前的下載下傳進度傳進來,這樣 onProgressUpdate()方法就會很快 被調用,在這裡就可以進行 UI 操作了。
當下載下傳完成後,doInBackground()方法會傳回一個布爾型變量,這樣 onPostExecute()方 法就會很快被調用,這個方法也是在主線程中運作的。然後在這裡我們會根據下載下傳的結果來
彈出相應的 Toast 提示,進而完成整個 DownloadTask 任務。
簡單來說,使用 AsyncTask 的訣竅就是,在 doInBackground()方法中去執行具體的耗時 任務,在 onProgressUpdate()方法中進行 UI 操作,在 onPostExecute()方法中執行一些任務的 收尾工作。