標(biāo)簽:Android AsyncTask 源碼解析
1.關(guān)于AsyncTask
1.1 什么是AsyncTask?
根據(jù)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允許我們執(zhí)行后臺操作并在UI線程中更新結(jié)果,而不用去操作threads或handlers。這句解釋很明顯的告訴了我們:AsyncTask是一個(gè)thread和handler的封裝疟呐。
1.2 為什么使用AsyncTask?
既然AsyncTask只是一個(gè)封裝,那它到底幫我們解決了哪些細(xì)節(jié)上的問題呢唐全?除了提供更簡明的接口之外,當(dāng)我們單純的使用thread+handler的組合時(shí)蕊玷,其實(shí)我們忽略了線程所帶來的一系列問題邮利,比如創(chuàng)建線程的開銷、如何管理線程等等垃帅,特別是當(dāng)多任務(wù)情況下延届,情況會更加復(fù)雜。
2.源碼解析
*注:源碼基于api-24
源碼點(diǎn)進(jìn)去一大堆贸诚,我們這里直接從任務(wù)被執(zhí)行開始看起方庭。同時(shí)為了避免深入細(xì)節(jié)無法自拔的情況,我先大體看一下整個(gè)的調(diào)用順序酱固,而不去太糾結(jié)具體實(shí)現(xiàn)械念。
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
可以看到子類直接調(diào)用了父類的execute()方法。該方法又調(diào)用了executeOnExecutor() 方法运悲。同時(shí)將sDefaultExecutor這個(gè)靜態(tài)變量傳遞給了executeOnExecutor方法龄减。那這個(gè)sDefaultExecutor又是什么鬼呢?
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
//省略...
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
原來sDefaultExecutor只是一個(gè)Executor接口班眯,而它的實(shí)現(xiàn)則是SerialExecutor這樣一個(gè)內(nèi)部類希停。我們先把這個(gè)類的具體實(shí)現(xiàn)放下烁巫,不過從類的名字就可以猜出個(gè)大概來,這是一個(gè)用來順序執(zhí)行任務(wù)的線程池類宠能。OK這個(gè)坑我們先邁過去亚隙,回頭再來繼續(xù)填它。再看看executeOnExecutor()方法:
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
//判斷當(dāng)前任務(wù)狀態(tài)
if (mStatus != Status.PENDING) {
switch (mStatus) {
//任務(wù)運(yùn)行中
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
//任務(wù)結(jié)束
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行先判斷當(dāng)mStatus的值违崇,即前任務(wù)的狀態(tài)阿弃,只有沒有運(yùn)的任務(wù)才能夠被運(yùn)行,否則將會拋出異常亦歉。再往下看恤浪,在將mStatus的值置為RUNNING之后,我看到了一個(gè)十分熟悉的方法onPreExecute()肴楷,而這個(gè)方法是個(gè)空實(shí)現(xiàn),具體在執(zhí)行任務(wù)之前要做些什么荠呐,是由我們自己去實(shí)現(xiàn)的赛蔫。23-24行突然冒出兩個(gè)新變量,mWorker和mFuture泥张,回到變量聲明和構(gòu)造函數(shù)處看看他們的實(shí)質(zhì)呵恢。
//變量聲明
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
...
//構(gòu)造函數(shù),變量初始化
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//...省略部分代碼
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
//...省略部分代碼
};
}
可以看到mWorker為一個(gè)WorkRunnale類媚创,該類為一個(gè)靜態(tài)抽象內(nèi)部類渗钉,包含了一個(gè)初始化參數(shù)Params[],并繼承了Callable接口(待實(shí)現(xiàn))钞钙。
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
而mFuture為FutureTask的一個(gè)實(shí)例鳄橘,F(xiàn)utureTask是Java并發(fā)編程中一個(gè)十分常見的類,主要用來異步執(zhí)行任務(wù)芒炼,并返回結(jié)果瘫怜。很顯然,這些特點(diǎn)都是我們需要本刽,但單純的Thread所不具備的鲸湃。FutureTask需要一個(gè)Callable接口來進(jìn)行初始化,而這里我們使用了mWorker這個(gè)變量子寓。
介紹了這么多暗挑,我們再捋一下思路:我們自己實(shí)現(xiàn)多XXXTask執(zhí)行了execute()方法,再調(diào)用了我們重寫多onPreExecute()方法后斜友,該方法最終把一個(gè)任務(wù)(mFuture)交給了一個(gè)串行執(zhí)行任務(wù)的線程池(sDefaultExecutor)去執(zhí)行炸裆。那么剩下的問題就只有以下幾個(gè)了:
1.任務(wù)(mFuture)具體做了些什么?
2.任務(wù)(mFuture)執(zhí)行完后蝙寨,如何通知UI線程的晒衩?
再回頭看看mWork中Callable的實(shí)現(xiàn):
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);
}
};
在這里我們發(fā)現(xiàn)一個(gè)十分熟悉的方法——doInBackground()嗤瞎,而該方法的簽名是protected abstract Result doInBackground(Params... params)。是我們在子類中必須去實(shí)現(xiàn)的听系,因此mFuture具體做的事情就是我們在doInBackground()中的具體實(shí)現(xiàn)贝奇。再看看最后一行postResult()(此時(shí)任務(wù)有可能并未完成):
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
再看看任務(wù)執(zhí)行結(jié)束后,mFuture中done()方法的具體實(shí)現(xiàn):
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);
}
}
可見靠胜,任務(wù)結(jié)束后同樣也調(diào)用了postResult()方法掉瞳。而該方法又是如何將結(jié)果傳遞給UI線程的呢?答案也很簡單——通過Handler浪漠,這里的getHandler()方法返回一個(gè)sHandler靜態(tài)成員變量陕习,其實(shí)現(xiàn)如下:
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;
}
}
}
可以看到,構(gòu)造器通過Looper.getMainLooper()來初始化了Hanlder址愿,這也就是為什么hanlderMessage的具體執(zhí)行是在UI線程(主線程)中的原因该镣。最后判斷消息的種類追驴,如果為MESSAGE_POST_PROGRESS就調(diào)用我們自己實(shí)現(xiàn)的onProgress方法沙绝;如果為MESSAGE_POST_RESULT就調(diào)用finish方法,而finish()方法又會判斷當(dāng)前任務(wù)是否執(zhí)行完成亲茅。若執(zhí)行完成就交給我們實(shí)現(xiàn)的onPostExecute()方法娘纷,若還未執(zhí)行完成就就給我們實(shí)現(xiàn)的onCancelled()方法嫁审。這樣一來整個(gè)AsyncTask的大致流程我們就走完了~
再次整理一下流程:
1.我們自己實(shí)現(xiàn)的xxxTask(繼承AsyncTask)執(zhí)行了execute()方法;
2.execute方法調(diào)用了executeOnExecutor()方法赖晶,為我們的異步任務(wù)指定了一個(gè)串行執(zhí)行任務(wù)的線程池律适;
3.該線程池調(diào)用了mFuture的call()方法,在子線程執(zhí)行了我們重寫的doInBackground()方法遏插,最終發(fā)送一個(gè)消息給handler(用主線程的looper初始化);
4.該handler根據(jù)消息類型的不同捂贿,執(zhí)行結(jié)束任務(wù)onPostExecute()或更新進(jìn)度的操作onProgressUpdate();
到此涩堤,我們常用的AsyncTask的方法眷蜓,是不是不用再去翻文檔我們也能寫出先后順序了呢,成就感滿滿噠~
3.細(xì)節(jié)問題
---待更新---
Todo-List
-
細(xì)節(jié)問題
- [x] 線程池相關(guān)
- [x] 線程池順序執(zhí)行任務(wù)的實(shí)現(xiàn)
- [x] 部分細(xì)節(jié)代碼
- [x] WorkerRunnable 和 AsyncTaskResult