在Android開(kāi)發(fā)道路上,有一個(gè)類你是無(wú)論如何都無(wú)法繞過(guò)去的。那就是AsyncTask,因?yàn)槭褂玫淖銐蚝?jiǎn)單,在面試中多線程很頻繁聊到這個(gè)。
AsyncTask的使用起始很簡(jiǎn)單,在源碼中類為抽象類 我們只需要復(fù)寫doInBackground方法即可完成子線程的業(yè)務(wù)編寫。我們從AsyncTask中的方法 onPreExecute()doInBackground() onPostExecute()onProgressUpdate()來(lái)入手分析AsyncTask的源碼
AsyncTask的對(duì)象一般是執(zhí)行execute()方法來(lái)啟動(dòng),我們來(lái)看一下
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
接著看executeOnExecutor
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
//此處省略一些
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
在方法中首先調(diào)用了onPreExecute()方法執(zhí)行在主線程中,然后講參數(shù)賦給了Worker對(duì)象,在后面我們會(huì)知道這是線程執(zhí)行單位。然后調(diào)用了線程調(diào)度器來(lái)執(zhí)行Future,這個(gè)后面會(huì)解釋到。
然后我們?cè)賮?lái)看一下線程池的調(diào)用情況
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) {
// 真正線程池調(diào)用
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
這塊代碼 首先講要執(zhí)行的代碼放到Tasks隊(duì)列中,然后判斷是否有任務(wù)執(zhí)行 如果線程池空閑則調(diào)用scheduleNext();方法 這個(gè)方法中完成任務(wù)的執(zhí)行
THREAD_POOL_EXECUTOR的初始化如下
public static final Executor THREAD_POOL_EXECUTOR;
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;
}
可能你看到這里已經(jīng)有點(diǎn)頭暈了,但是沒(méi)關(guān)系,此處我們放慢腳步來(lái)解釋下幾個(gè)名詞
-
THREAD_POOL_EXECUTOR
這個(gè)是用于任務(wù)執(zhí)行的線程池 ,所有的任務(wù)都是在這個(gè)線程池中完成調(diào)用 -
SerialExecutor
這個(gè)線程池用于用于任務(wù)的排隊(duì),默認(rèn)實(shí)現(xiàn)也能看出來(lái),它是串行執(zhí)行任務(wù)。 -
FutureTask
FutureTask一個(gè)可取消的異步計(jì)算, 使用子線程計(jì)算返回的結(jié)果Result作為泛型,并且將WorkerRunnable作為構(gòu)造參數(shù)傳入 -
WorkerRunnable
真正的子線程執(zhí)行單位
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;
}
};
首先設(shè)置 mTaskInvoked.set(true);標(biāo)識(shí)任務(wù)已經(jīng)執(zhí)行,然后調(diào)整線程的優(yōu)先級(jí),接著調(diào)用doInBackground(mParams); 因?yàn)閃orkerRunnable的call()方法會(huì)被FutureTask的run方法調(diào)用,所以doInBackground()方法最后執(zhí)行在子線程中。postResult(result);最后將結(jié)果返回到UI線程。
我們都知道Handler的作用很大程度在于線程間傳輸,我們首先看一下 postResult(result)方法
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
很熟悉的代碼 通過(guò)Handler將MESSAGE_POST_RESULT發(fā)送到目標(biāo)來(lái)處理,我們首先看一下AsyncTask類中的Handler是如何處理的
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;
}
}
}
直接很簡(jiǎn)單的在構(gòu)造函數(shù)上Looper.getMainLooper() 獲取UI線程的Looper
看到switch語(yǔ)句中有兩種類型 1. MESSAGE_POST_RESULT: 2. MESSAGE_POST_PROGRESS 這我們?cè)谄綍r(shí)的使用中再熟悉不過(guò)了 一個(gè)用來(lái)在UI 線程中獲取結(jié)果的 onPostExecute(),另外一個(gè)則是onProgressUpdate 用來(lái)刷新任務(wù)完成的進(jìn)度的。
接下來(lái)我們先看一下AsyncTask的finish方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
簡(jiǎn)單判斷下是否取消isCancelled(),如果取消則調(diào)用onCancelled(result);,否則將結(jié)果傳遞到onPostExecute(result);在這里我們可以得出一個(gè)結(jié)論,AsyncTask為什么不能中斷線程,在AsyncTask的方法中Cancel方法的調(diào)用只是在線程執(zhí)行完需要返回結(jié)果的時(shí)候做的一個(gè)標(biāo)記符而已。
PS 這里多說(shuō)幾句 Java最開(kāi)始的時(shí)候是沒(méi)有正式中斷線程的辦法,一般都是調(diào)用interrupt()來(lái)強(qiáng)制中斷,然后在Run()方法中來(lái)捕獲這個(gè)異常。我們?cè)谄綍r(shí)的開(kāi)發(fā)過(guò)程中一般使用Run方法中循環(huán) 然后使用一個(gè)volatieboolean變量來(lái)提前終止掉Run方法來(lái)達(dá)到中斷線程的目的。
到這里 我們已經(jīng)基本完成了AsyncTask的源碼分析了,因?yàn)锳syncTask的源碼是只有500行,所以看下來(lái)起始很輕松,如果有些類的代碼達(dá)到了一萬(wàn)多行的時(shí)候,我們應(yīng)該用巧方法來(lái)閱讀源碼,最常見(jiàn)的方法便是從使用的角度來(lái)反向查看代碼如何實(shí)現(xiàn)的,去粗取精 了解到整個(gè)類的是如何設(shè)計(jì)的就行,做到看完后心中已經(jīng)有了框架模樣就可以了,沒(méi)必要一行一行看下去也不現(xiàn)實(shí)。