轉(zhuǎn)載注明出處:http://www.reibang.com/p/26e1f7be4d0d
簡介
上一篇主要針對AsyncTask
內(nèi)部使用到的一些線程的技術(shù)進行了基本的講解骡湖,如果還沒有看過的同學(xué),可以點開這個AsyncTask 第二篇線程篇去查看一下峻厚。這一篇就從源代碼分析AsyncTask
的具體實現(xiàn)响蕴,也終于從第一篇的使用到了實現(xiàn)的思路。下面就直接開始了惠桃。
方法調(diào)度說明
在AsyncTask
里面其實我們最關(guān)心里面實現(xiàn)的思路了浦夷,這就需要結(jié)合一下AsyncTask
怎么使用辖试,才更方便的理解內(nèi)部的實現(xiàn),如果還有同學(xué)并不了解它的使用劈狐,可以查看AsyncTask 第一篇使用篇這篇文章罐孝。
所有的開始都是從調(diào)用AsyncTask.execute(params)
方法,我們直接看一下這個方法吧肥缔。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
在execute(params)
內(nèi)部直接調(diào)用了executeOnExecutor
方法莲兢,并將一個Executor
的實例化對象傳入,同時也將運行參數(shù)傳入续膳,我們來看一下executorOnExecutor
方法吧改艇。
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;
}
內(nèi)部居然就有了詳細的實現(xiàn),也有我們非常熟悉的一個方法onPreExecute()
姑宽,可以看出來遣耍,在我們調(diào)用了AsyncTask.execute(params)
方法后,緊接著就會調(diào)用onPreExecute()
方法炮车,這個方法我們可以復(fù)寫舵变,并做一些任務(wù)執(zhí)行前的一些操作。
在這個方法里面瘦穆,首先會對自身狀態(tài)進行判斷纪隙,如果是RUNNING
和FINISHED
狀態(tài)就會拋出異常,也就是前面提示的每一個實例化的AsyncTask
只能執(zhí)行一次扛或,如果執(zhí)行多次會拋出異常绵咱。判斷完畢后,將自身狀態(tài)設(shè)置為RUNNING
狀態(tài)熙兔,并調(diào)用onPreExecute()
方法悲伶,接著將參數(shù)傳入mWorker
中,執(zhí)行mFuture
住涉,那說明mFuture
即可以作為線程運行的結(jié)果麸锉,也可以作為一個線程執(zhí)行的任務(wù),根據(jù)上一篇關(guān)于線程的文章舆声,我們就可以大膽猜測花沉,mWorker
實現(xiàn)了Callable
接口,而mFuture
其實是一個FutureTask
的實例化對象媳握。
趕緊找到mWorker
的聲明碱屁。
private final WorkerRunnable<Params, Result> mWorker;
......
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
找到聲明處,緊接著找到了具體的類蛾找,果然和我們猜測一樣娩脾,mWorker
實現(xiàn)了Callable
接口,但是只是一個抽象類打毛,里面聲明了一個泛型的成員變量晦雨,沒有call()
具體實現(xiàn)架曹,我們直接去找mWorker
實例化的地方,看一下call()
方法的具體實現(xiàn)闹瞧。
public AsyncTask() {
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);
}
};
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);
}
}
};
}
我們可以看見在AsyncTask
構(gòu)造函數(shù)里面就會對mWorker
和mFuture
實例化绑雄,在mWorker
對象中的call()
方法里面,先設(shè)置了線程優(yōu)先級奥邮,然后調(diào)用了我們熟悉的方法doInBackground()
万牺,并獲取了運行的結(jié)果,調(diào)用了postResult()
方法將結(jié)果傳入洽腺。mFuture
實例化的類獲取了mWorkder
實例化對象脚粟,并復(fù)寫了done()
這個方法,很容易理解這個done()
方法是線程具體任務(wù)執(zhí)行完畢后調(diào)用的蘸朋,復(fù)寫done()
方法主要是保證獲取到執(zhí)行結(jié)果核无,我們看一下postResultIfNotInvoked()
這個方法就明白了。
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
在這個方法里面藕坯,也會將執(zhí)行結(jié)果傳入postResult()
方法团南。
在這里我們看見了兩個比較熟悉的方法,一個是doInBackground()
一個是postResult()
炼彪,我們先來看doInBackground()
吧吐根。
protected abstract Result doInBackground(Params... params);
是一個抽象方法,也就是說我們在繼承或者直接實例化實時必須實現(xiàn)她辐马。
再來看一下postResult()
拷橘。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
將執(zhí)行結(jié)果通過Handler傳入了UI線程中的某個方法,想必大家都猜到了最終會調(diào)用到onPostExecute(Result result)
喜爷,但是目前為止我們只是獲得了運行的結(jié)果冗疮,但是并沒有獲取到在執(zhí)行過程中的執(zhí)行狀態(tài)。去看一看publishProgress
一探究竟檩帐。
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
原來這個方法也是將用戶傳入的執(zhí)行狀態(tài)直接通過Handler傳到UI線程的某個方法术幔,對,就是onProgressUpdate
方法轿塔√卦福可以看見最關(guān)鍵的兩個異步消息的處理仲墨,結(jié)果和執(zhí)行狀態(tài)信息都是通過Handler傳到UI線程勾缭,直接看一下Handler的聲明。
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@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里面就處理了兩類消息目养,一個是拋出運行結(jié)果消息俩由,一個是拋出運行狀態(tài)的消息。如果是運行狀態(tài)癌蚁,直接回調(diào)用AsyncTask
的onProgressUpdate
方法幻梯,和大家猜想是一樣的兜畸。如果是運行結(jié)果,會調(diào)用finish
方法碘梢,我們看看這個方法咬摇,為什么不是直接調(diào)用onPostExecute
方法。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
很明顯煞躬,如果在執(zhí)行過程中肛鹏,用戶沒有去取消,就會調(diào)用onPostExecute
方法恩沛,如果取消了就會調(diào)用onCancelled
方法在扰。然后最終,會將AsyncTask
的執(zhí)行狀態(tài)變?yōu)?code>FINISHED狀態(tài)雷客,一旦置為這個狀態(tài)芒珠,再去調(diào)用AsyncTask.execute(params)
就會拋出異常,這個在調(diào)用該方法時候就會去判斷搅裙,大家可以去上面看一下這塊源代碼皱卓。
到目前為止,AsyncTask
內(nèi)部方法間的調(diào)度順序大家通過源代碼想必有了大體的認識呈宇。但是如果現(xiàn)在讓大家自己寫一個類似的類DemoTask好爬,大家會怎么實現(xiàn)?根據(jù)上一篇的文章甥啄,我們會直接實例化一個Executor去執(zhí)行FutureTask存炮,并使用Handler來處理異步線程間通信。這樣是正確的做法蜈漓,但是一旦當我們自定義的DemoTask被大量時候的時候穆桂,我們并不能對它有一個統(tǒng)一的管理,所以我們有必要看一下官方對于這一塊是怎么處理的融虽。
線程調(diào)度說明
大家記得在調(diào)用AsyncTask.execute()
方法時候享完,會有一個sDefaultExecutor
實例化對象出現(xiàn)過吧,很明顯有额,它是用來執(zhí)行FutureTask
的般又,而且是個常量,直接去看一下它的定義巍佑。
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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);
}
}
}
代碼很容易理解茴迁,它在執(zhí)行時候會將FutureTask
放入一個匿名Runnable
的執(zhí)行方法中,然后將這個匿名Runnable
添加到自身一個成員變量萤衰,如果首次調(diào)用這個方法堕义,會執(zhí)行調(diào)用scheduleNext
方法,使用線程池去運行這個匿名的Runnable
脆栋。如果當前匿名Runnable
中的FutureTask
執(zhí)行完畢倦卖,也會調(diào)用ScheduleNext
方法洒擦。
我們來看一下線程池THREAD_POOL_EXECUTOR
聲明的地方。
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS,
sPoolWorkQueue,
sThreadFactory);
前面這些常量通過字面含義就能大體了解含義了怕膛,如果有同學(xué)想知道具體含義熟嫩,可以去查看一下源代碼,我們現(xiàn)在僅看一下sPoolWorkQueue
這個參數(shù)褐捻。
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
很明顯邦危,它是一個用來存儲線程池中線程的隊列,而且最多能容納128個線程舍扰。而且由于這個線程池是全局的一個靜態(tài)常量倦蚪,所以在一個進程中所有我們實例化AsyncTask
的具體執(zhí)行任務(wù)都會被添加到這個線程池中。
至此關(guān)于AsyncTask
中線程的調(diào)度边苹,也有了一個清晰的脈絡(luò)陵且。
總結(jié)
雖然AsyncTask
是一個快過時的類,而且它不適合執(zhí)行長時間后臺操作个束,但是在許多場景我們依然會需要到它慕购,而且通過源代碼,我們可以對這種作者的思路做出一個很好的總結(jié)茬底,對Handler的使用場景和使用方法沪悲,有了更深的認識。至此阱表,我們也可以參考AsyncTask
的思路殿如,自定制適合自己的異步消息處理的機制。