安卓 - 原始碼 - AsyncTask
簡介
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的工作過程。