簡介
AsyncTask 是一個 Thread 和 Handler 的助手類。
通過該類,可以輕鬆的創建 需要把結果發佈到UI線程的短期後臺操作。
(長時間後臺操作推選使用 java.util.concurrent 的API)
在API 11前,線程池是一個普通的ThreadPoolExecutor,支持併發:
new ThreadPoolExecutor(5, 128, 10, TimeUnit.SECONDS,
LinkedBlockingQueue<Runnable>(10), ThreadFactory);
在API 11後,線程池是一個維護了Runnable隊列的SerialExecutor,支持串行:
new SerialExecutor();
注意到的是,SerialExecutor內部實際是通過一個支持併發的線程池工作的:
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
[2,4], CPU*2+1, 30, TimeUnit.SECONDS,
LinkedBlockingQueue<Runnable>(128), ThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
而AsyncTask支持通過executeOnExecutor執行在指定的線程池,所以如果需要執行併發任務的時候,可以直接使用
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
而無需重新自定義線程池。
基本行爲
AsyncTask的行爲被定義爲2塊:
-
泛型參數 <Params, Progress, Result>
用於定義AsyncTask執行時使用的3種參數的類型:public abstract class AsyncTask<Params, Progress, Result> {...} Params :執行時傳入的參數的類型; Progress :進度更新時傳出的參數的類型; Result :執行完成時返回的參數的類型;
-
執行步驟
AsyncTask執行時主要的4個步驟方法:@MainThread protected void onPreExecute() {} :在後臺任務開始前的初始化方法,執行在UI線程,可以用於設置任務 @WorkerThread protected abstract Result doInBackground(Params... params){...} :onPreExecute之後馬上執行,後臺任務的執行方法,也是AsyncTask的核心方法,在後臺線程中執行 執行過程中,可以使用publishProgress通知後臺任務的進度更新 執行結束時,返回的結果會作爲onPostExecute的參數 @MainThread protected void onProgressUpdate(Progress... values) {...} :調用publishProgress後執行,執行在UI線程,用於執行後臺進度變更時需要變化的邏輯 @MainThread protected void onPostExecute(Result result) {...} :後臺任務完成時調用,執行在UI線程,用於接收執行結果處理後臺任務執行完成的邏輯
工作原理
AsyncTask主要的工作可以概括成:
- 後臺耗時任務,AsyncTask的工作主體
- 在UI線程的任務進度通知以及任務完成通知
在AsyncTask的說明中提及,該類只是一個Thread和Handler的輔助類,而不是一個標準的線程操作框架:
AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
and does not constitute a generic threading framework.
其中涉及到的內容:
- Thread :後臺工作的所在線程,由預置或自定義線程池維護
- Handler:從後臺線程切換到UI線程的核心,完成所有後臺任務中對通知UI線程的通知操作
線程切換
AsyncTask中對Thread和Handler的處理切換,主要由以下的對象完成:
private final Handler mHandler;
:AsyncTask對象的成員,指向AsyncTask靜態成員sHandler
private static InternalHandler sHandler
= new InternalHandler(Looper.getMainLooper())
:傳入Looper.getMainLooper()說明運行在主線程
負責AsyncTask從工作線程切換到主線程,執行如onProgressUpdate等方法
private static class InternalHandler extends Handler {
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
:AsyncTaskResult<?> result在下面分析
這裏主要關注sHandler的工作內容,sHandler處理的工作主要有:
1.MESSAGE_POST_RESULT : 對應方法爲onPostExecute()
2.MESSAGE_POST_PROGRESS : 對應方法爲onProgressUpdate()
在該處可以推斷出:推送到sHandler的消息基本來自子線程,通過sHandler實現UI線程的切換
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
:推送到sHandler的消息的數據封裝,主要封裝了當前的AsyncTask和操作參數
1.mTask:需要執行UI線程任務的AsyncTask對象
2.mData:AsyncTask執行UI線程任務的參數,在推送<Progress>參數時,可以是多參數的
以上的部分完成UI線程的工作任務,且反映了:
AsyncTask 的 onPostExecute() 和 onProgressUpdate() 運行在UI線程依賴的是Handler機制。
執行任務
- 從execute開始
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
:調用execute方法時,實際上調用了executeOnExecutor方法
傳入的線程池,則是上面簡介中提到的SerialExecutor,一個串行執行任務的線程池
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) {
if (mStatus != Status.PENDING) ... ...
:檢查AsyncTask實例的運行狀態
AsyncTask每一個實例,只允許執行一次(execute)
除了PENDING,其餘狀態都會拋出IllegalStateException
mStatus = Status.RUNNING;
onPreExecute();
:修改爲運行中狀態,在UI線程中執行AsyncTask的預處理方法
mWorker.mParams = params;
exec.execute(mFuture);
:這裏涉及到了一個mWorker對象,屬於後臺線程運行部分,下一部分說明
大體上,mWorker是一個Callable,負責AsyncTask的後臺任務調用過程
return this;
}
:executeOnExecutor大體上負責了2個內容:
1.判斷當前執行狀態
2.使用傳入的線程池,執行AsyncTask的後臺任務
- 執行後臺任務
使用傳入的線程池執行AsyncTask的後臺任務,具體的執行流程,封裝在mWorker
private final WorkerRunnable<Params, Result> mWorker;
private static abstract class WorkerRunnable<Params, Result>
implements Callable<Result> {
Params[] mParams;
}
:mWorker是 WorkerRunnable類的實例
本質上是一個保存了Params參數的Callable對象
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
:設置調用狀態爲已被調用
在該狀態設置前,doInBackground被標識爲未調用
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
result = doInBackground(mParams);
:設置線程優先級爲後臺線程,執行doInBackground
} catch (Throwable tr) {
mCancelled.set(true);
:當發生異常時,設置AsyncTask取消狀態爲已取消
throw tr;
} finally {
postResult(result);
:發送執行結果,屬於執行完成的部分,後面介紹
}
return result;
}
};
:mWorker負責處理了doInBackground的邏輯
以及doInBackground完成後調用postResult發送執行結果
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException(..., e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
:mFuture是包裹mWorker的FutureTask對象
這裏的邏輯基本上只有一種情況會發生,即 doInBackground拋出異常或錯誤,
導致 get() 方法調用時拋出 ExecutionException,然後 done() 方法拋出 RuntimeException
- 發送執行結果
private Handler getHandler() {
return mHandler;
}
private Result postResult(Result result) {
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
:把執行結果發送到mHandler,意味着在主線程執行
case MESSAGE_POST_RESULT:
result.mTask.finish(result.mData[0]);
break;
:mHandler處理執行結果的邏輯,調用了mTask的finish方法
public final boolean isCancelled() {
return mCancelled.get();
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
:根據執行狀態選擇需要調用的方法
1.onCancelled() 即任務被取消
2.onPostExecute() 即任務完成
mCancelled爲true的情況有2種
1.調用了AsyncTask的cancel()方法取消任務
2.doInBackground()的過程中拋出異常,導致任務被取消
@MainThread
protected void onCancelled(Result result) {
onCancelled();
}
@MainThread
protected void onCancelled() {
}
@MainThread
protected void onPostExecute(Result result) {
}
:執行結果的方法都可以根據需求重寫
以上就是AsyncTask的工作過程。