標簽:Android AsyncTask 源碼解析
1.關于AsyncTask
1.1 什么是AsyncTask?
根據Google的官方文檔
This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
AsyncTask允許我們執行后臺操作并在UI線程中更新結果,而不用去操作threads或handlers。這句解釋很明顯的告訴了我們:AsyncTask是一個thread和handler的封裝。
1.2 為什么使用AsyncTask?
既然AsyncTask只是一個封裝,那它到底幫我們解決了哪些細節上的問題呢?除了提供更簡明的接口之外,當我們單純的使用thread+handler的組合時,其實我們忽略了線程所帶來的一系列問題,比如創建線程的開銷、如何管理線程等等,特別是當多任務情況下,情況會更加復雜。
2.源碼解析
*注:源碼基于api-24
源碼點進去一大堆,我們這里直接從任務被執行開始看起。同時為了避免深入細節無法自拔的情況,我先大體看一下整個的調用順序,而不去太糾結具體實現。
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
可以看到子類直接調用了父類的execute()方法。該方法又調用了executeOnExecutor() 方法。同時將sDefaultExecutor這個靜態變量傳遞給了executeOnExecutor方法。那這個sDefaultExecutor又是什么鬼呢?
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
//省略...
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
原來sDefaultExecutor只是一個Executor接口,而它的實現則是SerialExecutor這樣一個內部類。我們先把這個類的具體實現放下,不過從類的名字就可以猜出個大概來,這是一個用來順序執行任務的線程池類。OK這個坑我們先邁過去,回頭再來繼續填它。再看看executeOnExecutor()方法:
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
//判斷當前任務狀態
if (mStatus != Status.PENDING) {
switch (mStatus) {
//任務運行中
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
//任務結束
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
5-17行先判斷當mStatus的值,即前任務的狀態,只有沒有運的任務才能夠被運行,否則將會拋出異常。再往下看,在將mStatus的值置為RUNNING之后,我看到了一個十分熟悉的方法onPreExecute(),而這個方法是個空實現,具體在執行任務之前要做些什么,是由我們自己去實現的。23-24行突然冒出兩個新變量,mWorker和mFuture,回到變量聲明和構造函數處看看他們的實質。
//變量聲明
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
...
//構造函數,變量初始化
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//...省略部分代碼
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
//...省略部分代碼
};
}
可以看到mWorker為一個WorkRunnale類,該類為一個靜態抽象內部類,包含了一個初始化參數Params[],并繼承了Callable接口(待實現)。
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
而mFuture為FutureTask的一個實例,FutureTask是Java并發編程中一個十分常見的類,主要用來異步執行任務,并返回結果。很顯然,這些特點都是我們需要,但單純的Thread所不具備的。FutureTask需要一個Callable接口來進行初始化,而這里我們使用了mWorker這個變量。
介紹了這么多,我們再捋一下思路:我們自己實現多XXXTask執行了execute()方法,再調用了我們重寫多onPreExecute()方法后,該方法最終把一個任務(mFuture)交給了一個串行執行任務的線程池(sDefaultExecutor)去執行。那么剩下的問題就只有以下幾個了:
1.任務(mFuture)具體做了些什么?
2.任務(mFuture)執行完后,如何通知UI線程的?
再回頭看看mWork中Callable的實現:
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
在這里我們發現一個十分熟悉的方法——doInBackground(),而該方法的簽名是protected abstract Result doInBackground(Params... params)。是我們在子類中必須去實現的,因此mFuture具體做的事情就是我們在doInBackground()中的具體實現。再看看最后一行postResult()(此時任務有可能并未完成):
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
再看看任務執行結束后,mFuture中done()方法的具體實現:
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("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
可見,任務結束后同樣也調用了postResult()方法。而該方法又是如何將結果傳遞給UI線程的呢?答案也很簡單——通過Handler,這里的getHandler()方法返回一個sHandler靜態成員變量,其實現如下:
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
可以看到,構造器通過Looper.getMainLooper()來初始化了Hanlder,這也就是為什么hanlderMessage的具體執行是在UI線程(主線程)中的原因。最后判斷消息的種類,如果為MESSAGE_POST_PROGRESS就調用我們自己實現的onProgress方法;如果為MESSAGE_POST_RESULT就調用finish方法,而finish()方法又會判斷當前任務是否執行完成。若執行完成就交給我們實現的onPostExecute()方法,若還未執行完成就就給我們實現的onCancelled()方法。這樣一來整個AsyncTask的大致流程我們就走完了~
再次整理一下流程:
1.我們自己實現的xxxTask(繼承AsyncTask)執行了execute()方法;
2.execute方法調用了executeOnExecutor()方法,為我們的異步任務指定了一個串行執行任務的線程池;
3.該線程池調用了mFuture的call()方法,在子線程執行了我們重寫的doInBackground()方法,最終發送一個消息給handler(用主線程的looper初始化);
4.該handler根據消息類型的不同,執行結束任務onPostExecute()或更新進度的操作onProgressUpdate();
到此,我們常用的AsyncTask的方法,是不是不用再去翻文檔我們也能寫出先后順序了呢,成就感滿滿噠~
3.細節問題
---待更新---
Todo-List
-
細節問題
- [x] 線程池相關
- [x] 線程池順序執行任務的實現
- [x] 部分細節代碼
- [x] WorkerRunnable 和 AsyncTaskResult