博文出處:深入解析AsyncTask的原理,歡迎大家關注我的博客妆毕,謝謝慎玖!
前言
在初學 Android 的時候,AsyncTask 應該是大家都比較熟悉的笛粘。我們都知道 AsyncTask 可以在后臺開啟一個異步的任務,當任務完成后可以更新在 UI 上。而在 AsyncTask 中薪前,比較常用的方法有: onPreExecute 润努、 doInBackground 、 onPostExecute 和 onProgressUpdate 等示括。而上述的方法中除了 doInBackground 運行在子線程中铺浇,其他的都是運行在主線程的,相信大家對這幾個方法也了如指掌了垛膝。
在這里先劇透一下鳍侣, AsnycTask 原理就是“線程池 + Handler”的組合。如果你對Handler消息傳遞的機制不清楚吼拥,那么可以查看我上一篇的博文:《探究Android異步消息的處理之Handler詳解》倚聚,里面會有詳細的介紹。那么接下來凿可,就一起來看看 AsyncTask 實現(xiàn)的原理吧惑折!
class
public abstract class AsyncTask<Params, Progress, Result> {
...
}
AsyncTask 為抽象類,其中有三個泛型枯跑。這三個泛型相信大家都很熟悉了惨驶,第一個是傳遞的參數(shù)類型,第二個是任務執(zhí)行的進度敛助,第三個是任務執(zhí)行的結果類型了粗卜。如果其中某個不需要可以傳入Void。
線程池
那么我們先來看看 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<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(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);
從上面我們可以看到纳击,該線程池(即 THREAD_POOL_EXECUTOR)的核心線程數(shù)為 CPU 的核心數(shù)量 + 1续扔,最大線程數(shù)為 CPU 的核心數(shù)量 * 2 + 1,過剩線程的存活時間為1s评疗。這里要注意的是 sPoolWorkQueue 是靜態(tài)阻塞式的隊列灰追,意味著所有的 AsyncTask 用的都是同一個 sPoolWorkQueue ,也就是說最大的容量為128個任務婉烟,若超過了會拋出異常习霹。最后一個參數(shù)就是線程工廠了,用來制造線程加匈。
我們再來看看 AsyncTask 內部的任務執(zhí)行器 SERIAL_EXECUTOR 存璃,該執(zhí)行器用來把任務傳遞給上面的 THREAD_POOL_EXECUTOR 線程池。在 AsyncTask 的設計中雕拼,SERIAL_EXECUTOR 是默認的任務執(zhí)行器纵东,并且是串行的,也就導致了在 AsyncTask 中任務都是串行地執(zhí)行啥寇。當然偎球,AsyncTask 也是支持任務并行執(zhí)行的洒扎,這個點我們在下面再講。
/**
* 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 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);
}
}
}
可以從 SerialExecutor 的內部看到衰絮,是循環(huán)地取出 mActive 袍冷,并且把 mActive 放置到上面的 THREAD_POOL_EXECUTOR 中去執(zhí)行。這樣就導致了任務是串行地執(zhí)行的猫牡。
Handler
講完了線程池胡诗,那么剩下的就是 Handler 了。下面是 AsyncTask 內部實現(xiàn)的一個 Handler :
private static InternalHandler sHandler;
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
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;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
在源碼中淌友,有一個靜態(tài)的 sHandler 煌恢,還有定義了兩條消息的類型。一條表示傳送結果震庭,另一條表示傳送進度瑰抵。再來分析一下 InternalHandler 的源碼:在 InternalHandler 的 handleMessage 方法中,根據(jù)消息類型分別有不同的處理归薛。其中的 result.mTask 可以從 AsyncTaskResult 類中看到谍憔,就是 AsyncTask 本身。而后邊的方法有一些眼熟啊主籍。其中 finish 應該是在任務結束時回調的习贫,若任務完成會回調 onPostExecute 方法,否則會回調 onCancelled 方法千元;而消息類型為 MESSAGE_POST_PROGRESS 中的 onProgressUpdate 方法不就是我們在使用 AsyncTask 時重寫的那個方法么苫昌。在這里我們已經可以看出點端倪了。但是我們先賣個關子幸海,繼續(xù)向下看祟身。
構造器
再來看看 AsyncTask 的構造器:
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
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);
}
}
};
}
@WorkerThread
protected abstract Result doInBackground(Params... params);
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
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<Result>(this, result));
message.sendToTarget();
return result;
}
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
在構造器中創(chuàng)建了 WorkerRunnable 和 FutureTask 的對象,而在 WorkerRunnable 內部的 call 方法中會去執(zhí)行需要我們重寫的 doInBackground 方法物独。而如果在 doInBackground 方法中調用 publishProgress 方法袜硫,就會使用發(fā)送消息到 sHandler 的 handleMessage 方法,之后就調用了 onProgressUpdate 方法了挡篓,具體可見上面的 InternalHandler 中的代碼婉陷。最后如果任務結束了在 postResult 中發(fā)送消息給 sHandler ,就是要在 handleMessage 中拿到消息并且執(zhí)行上面分析過的 finish 方法了官研。
execute
最后我們來講講 execute 方法秽澳,以下是源碼:
@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;
}
@MainThread
protected void onPreExecute() {
}
在上面中可以看到我們平常使用的 execute 方法會去調用 executeOnExecutor 方法。而在 executeOnExecutor 方法內又會去調用 onPreExecute 方法戏羽。這也就是為什么 onPreExecute 方法是在任務開始運行之前調用的原因了担神。這里要注意的是,如果想讓 AsyncTask 并行地去執(zhí)行任務始花,那么可以在 executeOnExecutor 方法中傳入一個并行的任務執(zhí)行器妄讯,這樣就達到了并行的效果孩锡。
總結
好了,AsyncTask 的源碼大致就這些了捞挥,也分析地差不多了浮创。我們總共分成了 class 忧吟、線程池砌函、Handler 、構造器和 execute 五部分來分析溜族。這樣可能會給人比較散亂的感覺讹俊,但是連起來看就會對 AsyncTask 的原理更加了解了。那么煌抒,下面我們就來總結一下吧:
AsyncTask 的線程池的線程數(shù)量是和 CPU 的核心數(shù)相關的仍劈。而線程池的隊列是阻塞式的并且是有限的,最大容量為128寡壮。這也意味著 AsyncTask 不適合于做一些大型的贩疙、長期在后臺運行的任務。因為這樣可能導致著隊列的溢出况既,會拋出異常这溅。所以 AsyncTask 適合于一些小型的任務。
onProgressUpdate棒仍、 onCancelled 和 onPostExecute 等都是通過 handler 的消息傳遞機制來調用的悲靴。所以 AsyncTask 可以理解為“線程池 + Handler”的組合。
在 execute 方法中莫其,會先去調用 onPreExecute 方法癞尚,之后再在線程池中執(zhí)行 mFuture 。這時會調用 doInBackground 方法開始進行任務操作乱陡。 mWorker 和 mFuture 都是在構造器中初始化完成的浇揩。
AsyncTask 支持多線程進行任務操作,默認為單線程進行任務操作憨颠。
今天就到這里了胳徽,下次再見!
Goodbye ~~