Android 的系統(tǒng)異步工具類AsyncTask源碼解析

由于從wordpress將文章倒回,發(fā)現(xiàn)格式有點(diǎn)混亂,經(jīng)努力調(diào)整后依然有部分的格式還未調(diào)教好,請(qǐng)多多包涵.

分析AsyncTask或者闡述AsyncTask的博文有很多,本著授人予魚不如授人予漁的想法我想通過(guò)自主學(xué)習(xí)的方式去探索這個(gè)api,如果有闡述不當(dāng)?shù)牡胤綒g迎各位大神不吝斧正.本文將通過(guò)源碼學(xué)習(xí)分析以及demo實(shí)例驗(yàn)證的方式徹底的了解AsyncTask運(yùn)行的原理.

隨著開源社區(qū)的興旺,在目前android的開發(fā)中有著各種異步的工具以及框架,現(xiàn)在比較熱門的當(dāng)屬Rxjava+RxAndroid這個(gè)React的開源庫(kù),至于這個(gè)從Android1.5版本就開始提供的異步工具AsyncTask反而經(jīng)常出現(xiàn)在Android各類異步實(shí)現(xiàn)文章中的反面例子.我寫這篇文章有以下的意圖:一是通過(guò)源碼和實(shí)例去探討為什么AsyncTask一直被吐槽.二是了解學(xué)習(xí)AsyncTask的實(shí)現(xiàn)方式(只有了解原理,在使

用中遇到各式問(wèn)題才有對(duì)策).

關(guān)于AsyncTask的介紹以及使用例子可以移步官方開發(fā)者網(wǎng)站,這里就不多費(fèi)口舌.AsyncTask的存在的原因是在Android應(yīng)用運(yùn)行過(guò)程中,耗時(shí)的任務(wù)不能放在UI線程也就是我們常說(shuō)的主線程中執(zhí)行,必須開啟線程在后臺(tái)執(zhí)行,如果有執(zhí)行結(jié)果要通知到頁(yè)面上的話需要通過(guò)handler進(jìn)行子線程和UI線程的通信,而AsyncTask就是應(yīng)運(yùn)而生去簡(jiǎn)化這一過(guò)程的api.

現(xiàn)在進(jìn)入實(shí)現(xiàn)原理的正題,通過(guò)學(xué)習(xí)源碼的過(guò)程可以設(shè)想如果是要求自己實(shí)現(xiàn)一個(gè)這樣的異步工具應(yīng)當(dāng)怎么做,任何創(chuàng)造的前提是從模仿開始.筆者這邊使用的sdk version 23的源碼.首先是類的定義:

public abstract class AsyncTask {

? ? private static final String LOG_TAG = "AsyncTask";

? ? private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();

? ? private static final int CORE_POOL_SIZE = CPU_COUNT + 1;

? ? private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;

? ? private static final int KEEP_ALIVE = 1;

? ? private static final ThreadFactory sThreadFactory = new ThreadFactory() {

? ? private final AtomicInteger mCount = new AtomicInteger(1);

? ? public Thread newThread(Runnable r) {

? ? ? ? ?return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());

? ? }

? ? };

? ? private static final BlockingQueue sPoolWorkQueue =new LinkedBlockingQueue(128);

/**

* An {@link Executor} that can be used to execute tasks in parallel.

*/

public static final Executor THREAD_POOL_EXECUTOR

= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,

TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

AsyncTask是抽象類,根據(jù)使用的需要定義了三個(gè)泛型分別是傳入的參數(shù),執(zhí)行的Progress,以及執(zhí)行的結(jié)果.通過(guò)這一小段的源碼可以看到AsyncTask擁有一個(gè)靜態(tài)final的THREAD_POOL_EXECUTOR,這個(gè)線程池能夠運(yùn)行的線程最大數(shù)是通過(guò) cpu核心數(shù)*2+1 計(jì)算得出.并且在一個(gè)進(jìn)程中無(wú)論開發(fā)者寫出多少個(gè)AsyncTask的實(shí)現(xiàn)子類最終管理線程的只是這個(gè)大小為128的線程池.如果連續(xù)添加超過(guò)128個(gè)任務(wù),線程池就爆了(這也是被其他開發(fā)者詬病的地方,不過(guò)這樣的開發(fā)寫法是否符合規(guī)范也待商榷).現(xiàn)在接著往下看:

/**

* An {@link Executor} that executes tasks one at a time in serial

* order.? This serialization is global to a particular process.

*/

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static final int MESSAGE_POST_RESULT = 0x1;

private static final int MESSAGE_POST_PROGRESS = 0x2;

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

private static InternalHandler sHandler;

private final WorkerRunnable mWorker;

private final FutureTask mFuture;

private volatile Status mStatus = Status.PENDING;

private final AtomicBoolean mCancelled = new AtomicBoolean();

private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

private static class SerialExecutor implements Executor {

final ArrayDeque mTasks = new ArrayDeque();

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í)行的線程池構(gòu)建好了,現(xiàn)在輪到Exector SERIAL_EXECUTOR,看這個(gè)對(duì)象的命名為serial,感覺(jué)像是單個(gè)按順序的執(zhí)行器(非并發(fā)),我們接著往下看:

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

默認(rèn)的executor為SERIAL_EXECUTOR 并帶上了volatile(這里帶上volatile類型修飾符的原因是在多線程編程中開發(fā)者可以通過(guò)調(diào)用AsyncTask.setDefaultExecutor(Executor executor)使用自定義的Executor替換SERIAL_EXECUTOR.此處先不急著看SERIAL_EXECUTOR.接著是

private static InternalHandler sHandler;

又是一個(gè)靜態(tài)的對(duì)象InternalHandler,貼出類聲明:

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;

}

}

}

根據(jù)對(duì)象名稱有internal說(shuō)明是一個(gè)內(nèi)部的事件handler,構(gòu)造函數(shù)帶有super(Looper.getMainLooper())說(shuō)明是這個(gè)Handler的handleMessage(Message msg)的方法是在主線程中調(diào)用,分別有兩個(gè)事件是處理result信息和progress信息這里也就滿足了之前類設(shè)計(jì)需求需要在主線程中反饋執(zhí)行結(jié)果.剩下的

private final WorkerRunnable mWorker;

private final FutureTask mFuture;

private volatile Status mStatus = Status.PENDING;

private final AtomicBoolean mCancelled = new AtomicBoolean();

private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

將放在通過(guò)調(diào)用類的構(gòu)造函數(shù)以及執(zhí)行的流程中講訴.以上我們將AsyncTask的屬性分析完畢,接下來(lái)通過(guò)實(shí)例調(diào)用過(guò)程來(lái)進(jìn)行源碼旅程.Demo的例子可以查看Github.

我們創(chuàng)建一個(gè)AsyncTask的子類TimeConsumingTask,模擬后臺(tái)耗時(shí)的操作以及反饋結(jié)果給UI線程.

public class TimeConsumingTask extends AsyncTask {

private static String TAG = "TimeConsumingTask";

private WeakReference mHandler;

public static final String TAG_RESULT = "result";

private static volatile int sExecutionCount ;

public TimeConsumingTask(Handler handler) {

mHandler = new WeakReference(handler);

}

@Override

protected void onPreExecute() {

Log.d(TAG, "onPreExecute");

}

@Override

protected Boolean doInBackground(Integer... params) {

Log.d(TAG,"execute count is :"+ ++sExecutionCount);

for (Integer num : params) {

try {

Thread.sleep(num * 1000);

//will call onProgressUpdate()

publishProgress(num);

} catch (InterruptedException e) {

e.printStackTrace();

return false;

}}


return true;

}

@Override

protected void onProgressUpdate(Integer... values) {

for (Integer value : values) {

Log.d(TAG, "onProgressUpdate result: " + value);

if (null != mHandler.get()) {

Message message = new Message();

message.what = value;

mHandler.get().sendMessage(message);

}

}

}

@Override

protected void onPostExecute(Boolean aBoolean) {

Log.d(TAG, "onPostExecute result: " + aBoolean);

if (null != mHandler.get()) {

Message message = new Message();

message.getData().putBoolean(TAG_RESULT, aBoolean);

mHandler.get().sendMessage(message);

}}}

這里構(gòu)造方法我是通過(guò)傳入一個(gè)弱引用的主線程的handler進(jìn)行運(yùn)行結(jié)果的反饋,雖然只是demo還是希望寫的嚴(yán)謹(jǐn)些.子類會(huì)率先調(diào)用父類的構(gòu)造方法,此時(shí)我們來(lái)關(guān)注AsyncTask的構(gòu)造方法,里面包含了剛才未說(shuō)明的兩個(gè)屬性WorkerRunnable和FutureTask,FutureTask是java1.5引入的api,源碼說(shuō)明是A cancellable asynchronous computation.具體的可以建議讀者去好好學(xué)習(xí)下,當(dāng)下android很多流行的開源庫(kù)中實(shí)現(xiàn)都離不開FutureTask,這里就不做介紹.我們來(lái)看AsyncTask的構(gòu)造函數(shù):

/**

* Creates a new asynchronous task. This constructor must be invoked on the UI thread.

*/

public AsyncTask() {

mWorker = new WorkerRunnable() {

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(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 static abstract class WorkerRunnable implements Callable {

Params[] mParams;

}

private void postResultIfNotInvoked(Result result) {

final boolean wasTaskInvoked = mTaskInvoked.get();

if (!wasTaskInvoked) {

postResult(result);

}}

private Result postResult(Result result) {

@SuppressWarnings("unchecked")

Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,

new AsyncTaskResult(this, result));

message.sendToTarget();

return result;

}

我們可以看到WorkerRunnable是實(shí)現(xiàn)Callable在call方法中修改了運(yùn)行標(biāo)識(shí)|設(shè)置線程優(yōu)先級(jí)|以及真正的運(yùn)行doInBackground(Param)的方法,以及在運(yùn)行結(jié)束后調(diào)用postResult(result).其中 Binder.flushPendingCommands();這句的調(diào)用可能很多朋友不甚熟悉,可以點(diǎn)擊方法跳轉(zhuǎn)至源碼查看說(shuō)明,這里留個(gè)懸念.在FutureTask的主要是重寫了done()的回調(diào)進(jìn)行如果是未調(diào)用后臺(tái)方法就結(jié)束了異步任務(wù)的判斷,并拋出異常,此處可以發(fā)現(xiàn)好的api是在方法命名中就清楚的告訴了閱讀者意圖.此處的getHandler()就是通過(guò)lazyInit的方式獲取剛才說(shuō)到的變量InternalHandler進(jìn)行通信.

我們看完了構(gòu)造方法,現(xiàn)在來(lái)看AsyncTask的調(diào)用方法,AsyncTask的api設(shè)計(jì)十分簡(jiǎn)單,可調(diào)用方法execute(Params...)/cancel(boolean mayInterruptIfRunning)/...,接下來(lái)看下一般繼承AsyncTask一般要重寫的四個(gè)方法:onPreExecute(),doInBackground(Param...), onProgressUpdate(Progress... values) ,onPostExecute(Result result),接下來(lái)會(huì)講解這四個(gè)方法在源碼中被調(diào)用的時(shí)機(jī).我們先看下核心方法execute(Params...).進(jìn)入源碼:

@MainThread

public final AsyncTask execute(Params... params) {

return executeOnExecutor(sDefaultExecutor, params);

}

@MainThread

public final AsyncTask 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;

}

在方法頭加入了google annotation@MainThread,如果還不了解google annotation的朋友也可以上官方開發(fā)者網(wǎng)站上搜索進(jìn)行了解.說(shuō)明execute方法需要運(yùn)行在主線程中.execute的方法調(diào)用了executeOnExecutor并傳入剛才看到的sDefaultExecutor也就是SERIAL_EXECUTOR以及AsyncTask中三個(gè)泛型中的第一個(gè)Param作為參數(shù).這里在executeOnExecutor運(yùn)行中對(duì)Status進(jìn)行了檢查,如果非PENDING態(tài)則拋出異常.Status只有PENDING/RUNNING/FINISHED,三種狀態(tài),初始化的時(shí)候是PENDING態(tài),這也是我們不能對(duì)同一個(gè)task反復(fù)調(diào)用execute的原因.更改狀態(tài)之后就調(diào)用了 onPreExecute();所以開發(fā)者繼承AsyncTask重寫的四大方法中第一個(gè)onPreExecute()是運(yùn)行在主線程中.

exec.execute(mFuture);

AsyncTask的sDefaultExecutor開始執(zhí)行我們?cè)跇?gòu)造函數(shù)中初始化的futureTask了.此處讓我們將目光轉(zhuǎn)向sDefaultExecutor的默認(rèn)賦值SERIAL_EXECUTOR:

private static class SerialExecutor implements Executor {

final ArrayDeque mTasks = new ArrayDeque();

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);}}}

好的代碼總是簡(jiǎn)潔明快,通過(guò)ArrayDeque 存儲(chǔ)傳入的任務(wù),并在scheduleNext通過(guò)THREAD_POOL_EXECUTOR.execute(task)的方式進(jìn)行任務(wù)調(diào)用,這里就不多做闡述了,這個(gè)Executor做了和它類名一樣的實(shí)行就是序列化執(zhí)行列表中的任務(wù).SERIAL_EXECUTOR是在3.0版本后加入的,說(shuō)明3.0版本后AsyncTask默認(rèn)不是并行化執(zhí)行任務(wù)而是順序執(zhí)行.也就是說(shuō)在3.0之前的AsyncTask可以同時(shí)有5個(gè)任務(wù)在執(zhí)行,而3.0之后的AsyncTask同時(shí)只能有1個(gè)任務(wù)在執(zhí)行.

之前在文章中已經(jīng)講述在WorkerRunnable的call()方法中調(diào)用了耗時(shí)操作方法doInBackground(Params...),那在后臺(tái)執(zhí)行的過(guò)程中更新UI的方法onProgressUpdate(Progress... values)又是怎么被調(diào)用的,根據(jù)官方文檔在doInBackground方法中需要post結(jié)果到主線程的時(shí)候會(huì)調(diào)用publishProgress(Progress...)方法.而這個(gè)方法和主線程有關(guān)系我相信讀者已經(jīng)有一個(gè)概念該方法中是通過(guò)往IntervalHandler發(fā)出消息來(lái)實(shí)現(xiàn):

@WorkerThread

protected final void publishProgress(Progress... values) {

if (!isCancelled()) {

getHandler().obtainMessage(MESSAGE_POST_PROGRESS,

new AsyncTaskResult(this, values)).sendToTarget();

}

}

這邊提一下方法頭的googleAnnotation @WorkerThread說(shuō)明該方法只能在工作線程中被調(diào)用.

Demo地址:在使用Demo時(shí)候可以通過(guò)DDMS的Thread監(jiān)控功能進(jìn)行AsyncTask的線程池監(jiān)控驗(yàn)證.

這里只是拋磚引玉寫一篇AsyncTask的源碼分析,希望各位大神能熱心參與android異步編程的討論.

Android異步一些輕量實(shí)現(xiàn)的討論文章:https://medium.com/@ali.muzaffar/handlerthreads-and-why-you-should-be-using-them-in-your-android-apps-dc8bf1540341#.6de7zdbii

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容