android 原始碼分析(五AsyncTask機制詳解)
AsyncTask機制詳解
AsyncTask用法回顧
AsyncTask類主要用到的幾個內部回撥函式有:doInBackground()、onPreExecute()、onPostExecute()、onProgressUpdate()。正是這幾個回撥函式構成了AsynTask類的使用邏輯結構。
注意:每個AsyncTask子類必須至少複寫doInBackGround()方法。
函式名
解釋
onPreExecute()
準備執行(該回調函式在任務被執行之後立即由UI執行緒呼叫。這個步驟通常用來完成在使用者UI上顯示進度條等相關操作)。
doInBackground(Params...)
正在後臺執行(該回調函式由後臺執行緒在onPreExecute()方法執行結束後立即被呼叫。通常在這裡執行耗時的後臺計算。計算的結果必須由該函式返回,並被傳遞到onPostExecute()中處理。在該函式內也可以使用
publishProgress()來發布進度值,這些進度值將會在onProgressUpdate()中被接收併發布到UI執行緒)。
onProgressUpdate(Progress...)
進度更新(該函式由UI執行緒在publishProgress()方法呼叫完後被呼叫,一般用於動態地更新一個進度條)。
onPostExecute(Result )
完成後臺任務(當後臺計算結束後被呼叫,後臺計算的結果會被作為引數傳遞給這一函式)。
函式回撥關係:

image.png
通過上方函式呼叫關係,我們可以總結出一些資料傳遞關係。如下:
- execute( )向doInBackground( )傳遞資料。
- doInBackground( )的返回值會傳遞給onPostExecute( )。
- publishProgress( )向progressUpdate( )傳遞。
為了呼叫關係明確及安全,AsyncTask類在繼承時要傳入3個泛型:
public class MyAsyncTask extends AsyncTask<Params, Progress, Result>
• 第一個泛型對應execute( )向doInBackground( )傳遞的資料型別。
• 第二個泛型對應publishProgress( )向progressUpdate( )傳遞的資料型別。
• 第三個泛型對應doInBackground( )的返回值型別,此返回值將傳遞給onPostExecute( )方法。
AsyncTask執行機制梳理
AsyncTask在呼叫execute方法後,任務開始執行:
frameworks\base\core\java\android\os\AsyncTask.java
…… private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory); …… public final AsyncTask<Params, Progress, Result> execute(Params... params) { // 一個AsyncTask任務僅能被執行一次,不能重複執行的限制 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方法 onPreExecute(); mWorker.mParams = params; sExecutor.execute(mFuture); return this; }
從這段程式碼我們可以得出以下結論:
-
- 一個AsyncTask任務只能被執行一次,不能重複execute
-
- 呼叫AsyncTask的execute方法時,實際上是呼叫了執行緒池Executor的execute方法
Executor的execute方法應該接收的是一個Runnable物件,AsyncTask程式碼中,我們傳遞的是一個mFuture,那麼這個mFuture是什麼呢?
frameworks\base\core\java\android\os\AsyncTask.java
…… private final WorkerRunnable<Params, Result> mWorker; private final FutureTask<Result> mFuture; …… public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return doInBackground(mParams); } }; mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { Message message; Result result = null; …… result = get(); …… message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(AsyncTask.this, result)); message.sendToTarget(); } }; }
在AsyncTask的構造方法中,分別初始化了一個WorkerRunnable的物件mWorker,以及一個FutureTask的物件mFuture。我們先從mFuture開始,看看這兩個做了些什麼。
libcore\luni\src\main\java\java\util\concurrent\FutureTask.java
public class FutureTask<V> implements RunnableFuture<V>
libcore\luni\src\main\java\java\util\concurrent\RunnableFuture.java
public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }
從上面2個類,我們可以得知,FutureTask實際上是實現了Runnable介面和Future介面的一個類,因此當執行” sExecutor.execute(mFuture);
”時,也一定是執行的mFuture中的run方法。FutureTask是一個增強版的Runnable,他除了Runnable還實現了Future介面,Future介面又是做什麼的?
libcore\luni\src\main\java\java\util\concurrent\Future.java
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
簡單來說,Future介面就是定義任務取消、是否取消,是否完成、獲取結果的一個介面。
既然知道了mFuture是一個FutureTask,即是一個增強版的Runnable,那麼執行緒池Executor必然也是通過執行其run方法來實現相應的邏輯的,我們來看一下FutureTask的run方法做了什麼:
libcore\luni\src\main\java\java\util\concurrent\FutureTask.java
private final Sync sync; …… public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); sync = new Sync(callable); } …… public void run() { sync.innerRun(); } ……
由程式碼可知,FutureTask的run方法實際上是呼叫了Sync類的innerRun方法,而Sync是在FutureTask構造方法中進行的初始化,那麼回憶一下AsyncTask構造方法初始化的過程,我們在構建mFuture物件的時候傳遞了一個WorkerRunnable的物件mWorker:
frameworks\base\core\java\android\os\AsyncTask.java
…… private final WorkerRunnable<Params, Result> mWorker; private final FutureTask<Result> mFuture; …… public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return doInBackground(mParams); } }; mFuture = new FutureTask<Result>(mWorker) { …… }; }
mWorker是WorkerRunnable的一個子類,並實現了其call()方法,在這個call()方法中,我們看到了一個很關鍵的程式碼“return doInBackground(mParams);”,因此可以猜想,最終實際執行線上程池中的邏輯,實際上是這個mWorker的call()方法。
那麼WorkerRunnable又是什麼呢?
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams; }
libcore\luni\src\main\java\java\util\concurrent\Callable.java
public interface Callable<V> { V call() throws Exception; }
由程式碼可知,WorkerRunnable是Callable<V>介面的一個子類,他只有一個抽象方法:call方法,這個方法是有返回值的,他返回一個泛型V。
帶入到我們的實際程式碼邏輯中,在我們的mWorker中,這個call方法返回了我們doInBackground方法執行的結果。
知道了mWorker是什麼,我們返回來看FutureTask的物件mFuture中的邏輯:
libcore\luni\src\main\java\java\util\concurrent\FutureTask.java
private final Sync sync; …… public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); sync = new Sync(callable); } …… public void run() { sync.innerRun(); } ……
它將mWorker這個Callable<V>的子類作為引數,初始化了一個內部類Sync物件,並在run方法中呼叫了這個Sync物件的innerRun方法。
我們來看看Sync是什麼:
private final class Sync extends AbstractQueuedSynchronizer { …… private final Callable<V> callable; private V result; …… Sync(Callable<V> callable) { this.callable = callable; } …… void innerRun() { …… if (getState() == RUNNING) { // recheck after setting thread V result; try { result = callable.call(); } catch (Throwable ex) { setException(ex); return; } set(result); } …… } …… protected void set(V v) { sync.innerSet(v); } void innerSet(V v) { …… result = v; releaseShared(0); done(); return; } }
Sync物件的innerRun方法呼叫了“result = callable.call();”,並將得到的result最終通過innerSet方法進行了賦值,最終走到了“done()”方法。
Callable實際上就是我們的WorkerRunnable物件mWorker,這個call方法,實際上就是我們的mWorker的call方法:
mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return doInBackground(mParams); } };
這個call方法中,我們實際上呼叫了doInBackground方法,並得到了這個方法執行的結果:result。
doInBackground方法執行結束後,我們通過set方法,最終呼叫到了innerSet方法,在這innerSet方法中,我們最終呼叫了FutureTask 的物件mFuture 的done方法:
mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { Message message; Result result = null; …… result = get(); …… message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(AsyncTask.this, result)); message.sendToTarget(); } };
我們看到done方法通過一個sHandler物件傳送了一個Message,看下這個sHandler物件的handleMessage方法做了什麼:
private static final InternalHandler sHandler = new InternalHandler(); private static class InternalHandler extends Handler { @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; case MESSAGE_POST_CANCEL: result.mTask.onCancelled(); break; } } }
可以看到,在what = MESSAGE_POST_RESULT的時候,他執行了:
result.mTask.finish(result.mData[0]);
這個finish方法其實呼叫的是當前這個AsyncTask的finish方法,這個finish方法中,呼叫了我們的onPostExecute方法,且因為是通過Handler發訊息來呼叫的,因此這個onPostExecute方法當前執行到了主執行緒。程式碼如下:
private void finish(Result result) { if (isCancelled()) result = null; onPostExecute(result); mStatus = Status.FINISHED; }
因此,由上方程式碼得到結論:
-
onPreExecute():UI執行緒執行。在execute(Params... params)被呼叫後立即執行,一般用來在執行後臺任務前的一些初始化操作
-
doInBackground(Params... params):子執行緒執行。在onPreExecute()完成後加入到執行緒池等待執行,用於執行耗時操作,此方法將接收到execute傳遞的引數。任務執行完畢,返回結果。
-
onPostExecute(Result result):UI執行緒執行。當後臺操作結束時,此方法將會被呼叫,doInBackground返回的Result將做為引數傳遞到此方法中,可以執行收尾操作。
AsyncTask跟Handler誰更輕量
AsyncTask實際上是執行緒池 + Handler的結合,使用起來是AsyncTask更方便一些,但是使用時還是Handler更輕量一些。
細節
AsyncTask在3.0以後改為預設序列執行了,3.0以前是預設並行執行。