導(dǎo)語(yǔ)
AsyncTask對(duì)Android開(kāi)發(fā)者來(lái)說(shuō)并不陌生,當(dāng)有耗時(shí)任務(wù)并涉及UI交互,AsyncTask可是處理異步任務(wù)的利器。AsyncTask使用也很方便,開(kāi)發(fā)的時(shí)候多留意不要內(nèi)存泄漏,一般處理方法就是把AsyncTask寫(xiě)成靜態(tài)內(nèi)部類(lèi)的形式。
使用方法
new AsyncTask<Integer, Integer, Boolean>() {
private int NUM = 0;
@Override
protected void onPreExecute() {
super.onPreExecute();
textView.setText("onPreExceute");
}
@Override
protected Boolean doInBackground(Integer... integers) {
for (int i = 0; i < 20; i++) {
try {
NUM ++;
publishProgress(NUM);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return NUM == 20;
}
@Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
textView.setText("onPostExcute: " + aBoolean);
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
textView.setText("onProgressUpdate: " + values[0]);
}
@Override
protected void onCancelled(Boolean aBoolean) {
super.onCancelled(aBoolean);
textView.setText("onCancelled: " + aBoolean);
}
@Override
protected void onCancelled() {
super.onCancelled();
textView.setText("onCancelled");
}
}.execute(1);
關(guān)鍵方法
onPreExecute、doInBackground、publishProgress、onPostExecute、onProgressUpdate、onCancelled是AsyncTask的幾個(gè)關(guān)鍵方法,開(kāi)發(fā)者可處理自己的邏輯。除了doInBackground在異步線程執(zhí)行外,publishProgress可在任意線程處理,其他方法都是在UI線程處理。publishProgress和onProgressUpdate配合使用。
參數(shù)
Integer, Integer, Boolean,在AsyncTask三個(gè)參數(shù)的呈現(xiàn)形式是:Params,Progress,Result,從字面意思我們就知道,Params即入?yún)ⅲ琍rogress即進(jìn)度,Result即返回結(jié)果,可根據(jù)實(shí)際業(yè)務(wù)邏輯靈活配置。
源碼分析
從execute()開(kāi)始吧
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@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;
}
Status有三個(gè)值:PENDING、RUNNING、FINISHED,分別表示初始、運(yùn)行、結(jié)束三個(gè)狀態(tài)。
從executeOnExecutor方法里可以看出,一開(kāi)始執(zhí)行Status狀態(tài)就置成了RUNNING運(yùn)行狀態(tài),這里出現(xiàn)了關(guān)鍵方法之一 onPreExecute
,也就是執(zhí)行異步任務(wù)doInBackground
前的一個(gè)狀態(tài),一般用來(lái)處理界面元素初始化相關(guān),運(yùn)行在UI線程。下面兩行代碼則開(kāi)啟了doInBackground
的工作:
mWorker.mParams = params;
exec.execute(mFuture);
mWorker是什么呢?mFuture又是什么呢?我們知道exec是一個(gè)Executor對(duì)象,說(shuō)明它是一個(gè)線程池,那么可以知道m(xù)Future應(yīng)該是Runnable或Callable對(duì)象。mWorker對(duì)象則承載了入?yún)ⅲ蚼Future肯定是依賴(lài)關(guān)系。繼續(xù)往下深入,一探mFuture和mWorker的究竟。
在AsyncTask構(gòu)造方法里面,發(fā)現(xiàn)了這兩個(gè)對(duì)象的初始化相關(guān):
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
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);
}
}
};
}
原來(lái)mWorker是一個(gè)Runnable,mFuture是一個(gè)FutureTask,mWorker用mFuture來(lái)承載。
FutureTask在平時(shí)開(kāi)發(fā)過(guò)程中用的較少,可能很多開(kāi)發(fā)者對(duì)它還有些陌生。這里做個(gè)簡(jiǎn)單介紹:FutureTask是一個(gè)用來(lái)執(zhí)行異步任務(wù)的類(lèi),同時(shí)當(dāng)程序執(zhí)行完成之后還會(huì)返回運(yùn)算的結(jié)果。官方釋義:這是一個(gè)可以取消的異步計(jì)算,該類(lèi)提供了Future的基本實(shí)現(xiàn),具有啟動(dòng)和取消運(yùn)算,查詢(xún)運(yùn)算是否結(jié)束,并且檢查返回計(jì)算的結(jié)果,該結(jié)果只能在運(yùn)行完成之后才能獲取到,如果程序沒(méi)有運(yùn)行結(jié)束,則get()
將會(huì)阻塞。程序運(yùn)行結(jié)束之后,無(wú)法重新啟動(dòng)或者是取消程序(除非調(diào)用runAndReset
方法)。FutureTask可以承載Callable和Runnable,兩者的區(qū)別是:Callable可以攜帶返回參數(shù),而Runnable不支持。
我們來(lái)看看mWorker
的實(shí)現(xiàn):
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
WorkerRunnable是一個(gè)抽象類(lèi),繼承自Callable,并攜帶了Result參數(shù),由于AsyncTask是一個(gè)帶結(jié)果返回的對(duì)象,所以用Callable實(shí)現(xiàn)。這里可以知道AsyncTask構(gòu)造方法里的mWorker即是WorkerRunnable的具體實(shí)現(xiàn),抽象類(lèi)里只是承載了入?yún)ⅰ?/p>
到這里,就清楚AsyncTask整體的運(yùn)行模式了:Executor —> FutureTask —> Callable 。內(nèi)部維護(hù)一個(gè)線程池,線程池處理異步任務(wù),異步任務(wù)承載Callable進(jìn)行任務(wù)的執(zhí)行。
繼續(xù)深入,mWoker就類(lèi)似一個(gè)帶任務(wù)的小兵,具體的執(zhí)行工作都在它身上完成。一探mWoker究竟吧。具體實(shí)現(xiàn)代碼再拎出來(lái):
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
在回調(diào)的call方法里,我們發(fā)現(xiàn)關(guān)鍵方法之二doInBackground
,說(shuō)明異步任務(wù)在這里執(zhí)行,返回了Result對(duì)象。Process.setThreadPriority設(shè)置了線程優(yōu)先級(jí),這里任務(wù)在后臺(tái)執(zhí)行,所以?xún)?yōu)先級(jí)設(shè)置成THREAD_PRIORITY_BACKGROUND。關(guān)于Binder.flushPendingCommands(),官方釋義:將當(dāng)前線程中掛起的任何綁定命令刷新到內(nèi)核驅(qū)動(dòng)程序中。在執(zhí)行可能很長(zhǎng)時(shí)間阻塞的操作之前調(diào)用此功能是有用的,以確保任何掛起的對(duì)象引用已被釋放,以防止進(jìn)程對(duì)對(duì)象持有比它所需時(shí)間更長(zhǎng)的時(shí)間。這里不做深究。異步任務(wù)執(zhí)行完畢又是如何告知UI線程的呢?這里的邏輯我們要看FutureTask的具體實(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);
}
}
};
可以看出當(dāng)任務(wù)執(zhí)行完畢,即在done方法回調(diào)里由postResultIfNotInvoked處理:
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
可以看出返回的結(jié)果對(duì)象Result最終通過(guò)postResult方法執(zhí)行,去看看:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
發(fā)現(xiàn)這就是我們常用的handler啊,這里發(fā)送了一條msg.what=MESSAGE_POST_RESULT,msg.object=AsyncTaskResult的消息給getHandler()。繼續(xù)看看getHandler()怎么處理的:
private Handler getHandler() {
return mHandler;
}
這。。。不是我想要的結(jié)果啊。好吧,繼續(xù)追蹤mHandler。才發(fā)現(xiàn)早在AsyncTask構(gòu)造方法里就對(duì)mHandler進(jìn)行了初始化。
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
好吧,繼續(xù)看getMainHandler()具體實(shí)現(xiàn):
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
繼續(xù)吧,看InternalHandler具體實(shí)現(xiàn):
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}
終于找到了handler的具體實(shí)現(xiàn),這里發(fā)現(xiàn)了關(guān)鍵方法之三onProgressUpdate
,可以看到他處理兩類(lèi)消息:MESSAGE_POST_RESULT和MESSAGE_POST_PROGRESS。很顯然這里的邏輯都是在UI線程發(fā)生。MESSAGE_POST_RESULT處理異步任務(wù)執(zhí)行完返回的Result,可以知道MESSAGE_POST_PROGRESS應(yīng)該就是處理publishProgress發(fā)送的消息了。
看看publishProgress的實(shí)現(xiàn):
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
這里發(fā)現(xiàn)了關(guān)鍵方法之三publishProgress
,可以看出,MESSAGE_POST_PROGRESS通過(guò)publishProgress發(fā)出,和MESSAGE_POST_RESULT發(fā)送對(duì)象的參數(shù)不一樣,MESSAGE_POST_PROGRESS攜帶的是Progress,MESSAGE_POST_RESULT攜帶的是Result。這邏輯也是通的,看來(lái)AsyncTaskResult也就是一個(gè)數(shù)據(jù)對(duì)象啦。看看具體實(shí)現(xiàn):
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
好了,到這里我們已經(jīng)理清異步任務(wù)執(zhí)行的結(jié)果或是執(zhí)行過(guò)程中的進(jìn)度是如何通知UI線程處理了。那么異步處理完成后返回的Result又是如何處理的呢?繼續(xù)往下看:
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;
}
對(duì)于Result的處理方式:result.mTask.finish(result.mData[0]);result.mTask即AsyncTask本身,我們具體看看它的finish方法具體實(shí)現(xiàn):
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
這里發(fā)現(xiàn)了關(guān)鍵方法之四onPostExecute
和關(guān)鍵方法之五onCancelled
。如果任務(wù)沒(méi)有被取消,則執(zhí)行onPostExecute,同時(shí)Status置于FINISHED,任務(wù)結(jié)束。
到這里,AsyncTask幾個(gè)關(guān)鍵方法的執(zhí)行時(shí)機(jī)和來(lái)龍去脈已經(jīng)清楚,通過(guò)handler進(jìn)行關(guān)聯(lián)處理。
我們知道AsyncTask可以同時(shí)處理多個(gè)Runnable任務(wù),那么內(nèi)部又是如何保證執(zhí)行順序呢?初步判斷是和線程池相關(guān),于是看看AsyncTask維護(hù)的線程池具體實(shí)現(xiàn):
線程池配置:
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
線程池的具體執(zhí)行類(lèi):
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
可以發(fā)現(xiàn)SerialExecutor內(nèi)部維護(hù)了一個(gè)ArrayDeque隊(duì)列,里面可以裝載很多Runnable。沒(méi)當(dāng)執(zhí)行一個(gè)Runnable的時(shí)候,將該Runnable添加到隊(duì)列尾部,每次執(zhí)行Runnable的時(shí)候從隊(duì)尾獲取Runnable對(duì)象。第一個(gè)Runnable任務(wù)執(zhí)行的時(shí)候,mActive==null,所以會(huì)去執(zhí)行scheduleNext()方法并把該runnable賦值給mActive,當(dāng)?shù)诙€(gè)Runnable執(zhí)行的時(shí)候,mActive!=null,就不會(huì)去執(zhí)行scheduleNext了嗎?當(dāng)然不是,我們可以發(fā)現(xiàn)run方法回調(diào)里用了try finally方法,意思是任何一個(gè)Runnable,執(zhí)行完畢后都會(huì)去執(zhí)行scheduleNext方法。這樣相當(dāng)于保證每個(gè)Runnable任務(wù)都是等上個(gè)Runnable執(zhí)行完畢后才會(huì)去執(zhí)行。
好了,關(guān)于AsyncTask的源碼解析主要邏輯都在這了。其中涉及的一些細(xì)節(jié),可以自行去查找資料了解。比如用AutomicBoolean來(lái)判斷任務(wù)是否取消(mCancelled)或已經(jīng)開(kāi)始執(zhí)行(mTaskInvoked)。
為更好地理解AsyncTask,建議大家參照AsyncTask源碼,造個(gè)輪子,畢竟代碼量不大。