AsyncTask 完全解析
引言
我們知道,在 Android 中,UI 線程不能執(zhí)行耗時操作;在子線程中不能執(zhí)行更新 UI 的操作。如果需要在子線程中進行 UI 相關(guān)的操作,那么就需要借助 Android 中的異步消息機制(比如我們熟悉的Handler消息機制)才能完成。如果我們自己寫代碼來進行相關(guān)的處理,不僅麻煩,而且大部分的代碼都是相同的,AsyncTask 的出現(xiàn)就能幫我們省去大部分的代碼,并且可以非常靈活方便地從子線程切換到UI線程。今天就從 AsyncTask 的簡單使用到源碼進行解析,一步一步看看他是怎么實現(xiàn)的。
AsyncTask 的簡單使用
創(chuàng)建 AsyncTask 實現(xiàn)類
class DownLoadAsyncTask extends AsyncTask<String, Integer, Boolean> {
@Override
protected Boolean doInBackground(String... params) {
// 運行在子線程,執(zhí)行訪異步任務
Log.i("DownLoadAsyncTask", "doInBackground(): 開始執(zhí)行異步任務");
// publishProgress(Integer); // 調(diào)用更新進度方法
return downLoadImage(params[0]); // 下載圖片方法
}
@Override
protected void onPreExecute() {
// 運行在主線程,異步任務執(zhí)行前的準備工作
Log.i("DownLoadAsyncTask", "onPreExecute(): 執(zhí)行異步任務前的準備工作");
super.onPreExecute();
}
@Override
protected void onPostExecute(Boolean result) {
// 運行在主線程,異步任務執(zhí)行完成之后的回調(diào)
Log.i("DownLoadAsyncTask", "onPostExecute(): 異步任務執(zhí)行完成之后的回調(diào) => " + result);
super.onPostExecute(result);
}
@Override
protected void onProgressUpdate(Integer... progresses) {
// 運行在主線程,用于更新進度
// 注意:該方法需要在doInBackground()內(nèi)部調(diào)用publishProgress()方法并傳遞進度,否則不會執(zhí)行
Log.i("DownLoadAsyncTask", "onProgressUpdate(): 用于更新進度");
super.onProgressUpdate(progresses);
}
}
AsyncTask<String, Integer, Boolean> 泛型說明:
- 第一個泛型:doInBackground() 方法的參數(shù)類型
- 第二個泛型:onProgressUpdate() 方法的參數(shù)類型
- 第三個泛型:doInBackground() 方法的返回類型 和 onProgressUpdate() 方法的參數(shù)類型
開始執(zhí)行任務
String url = "https://www.baidu.com/img/bd_logo1.png";
DownLoadAsyncTask downLoadAsyncTask = new DownLoadAsyncTask();
downLoadAsyncTask.execute(url);
以上就是 AsyncTask 的基本用法。
源碼解析
構(gòu)造方法
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
/**
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
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;
}
};
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);
}
}
};
}
構(gòu)造方法說明:
- 最終調(diào)用的都是
AsyncTask(@Nullable Looper callbackLooper)方法,但是這個方法使用了@hide注解,開發(fā)者并不能直接調(diào)用。構(gòu)造方法雖然比較長,但是他并沒有任何的操作被執(zhí)行,只是初始化了mHandler、mWorker、mFuture幾個變量,并且將mWorker對象作為mFuture的構(gòu)造方法參數(shù)傳遞給了mFuture對象。 -
mHandler是MainHandler - 有一點需要注意:構(gòu)造方法只能在UI線程中調(diào)用
構(gòu)造方法中用到的部分對象說明:
- mHandler:Android Handler消息機制中的Handler對象,這里是
InternalHandler對象,暫時記住就行了,后面會粘貼出具體實現(xiàn)的代碼和說明class InternalHandler extends Handler:
- mWorker:實現(xiàn)
Callable接口的AsyncTask類的內(nèi)部類WorkerRunnable - mFuture:
FutureTask對象。FutureTask對象的繼承關(guān)系- class FutureTask<V> implements RunnableFuture<V>
- interface RunnableFuture<V> extends Runnable, Future<V>
執(zhí)行異步任務方法
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);// 調(diào)用內(nèi)部方法
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) { // 判斷狀態(tài)
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; // 將狀態(tài)設置為RUNNING
onPreExecute(); // 回調(diào)異步任務執(zhí)行前的準備工作方法
mWorker.mParams = params; // 將傳遞的參數(shù)賦值給 mWorker 對象的 mParams 字段
exec.execute(mFuture); // 執(zhí)行 mFuture
return this;
}
到這一步的時候,我們的任務已經(jīng)切換子線程中了。
方法說明:
- 判斷當前的狀態(tài),如果是
RUNNING或者是FINISHED就拋出異常 - 執(zhí)行回調(diào)方法
onPreExecute(),執(zhí)行異步任務前的準備工作,比如顯示進度對話框等 - 將
mFuture對象 交給exec.execute(mFuture)執(zhí)行
exec.execute(mFuture)說明:
exec:即 sDefaultExecutor;實現(xiàn) Executor接口的內(nèi)部類 SerialExecutor
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(); // 調(diào)用參數(shù) Runnable 對象的 run() 方法
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
通過上面 SerialExecutor 類的定義,我們可以看到 execute() 方法調(diào)用了它的參數(shù)(即mFuture)的run()方法,我們繼續(xù)查看mFuture 的 run() 方法
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
在該方法中主要是調(diào)用了 callable 對象的 call() 方法,我們一起看看 callable對象是從哪里來的。
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
查看 FutureTask 對象的構(gòu)造方法,我們發(fā)現(xiàn)callable對象是在構(gòu)造方法中初始化的。好,我們現(xiàn)在就只要知道 FutureTask 對象是在哪里初始化的,就知道 call() 方法的具體執(zhí)行內(nèi)容是什么了。那么你是否還記得我們在查看 AsyncTask 類的構(gòu)造方法時看到了它初始化幾個變量就有FutureTask 對象,所以在這里執(zhí)行的 call() 方法具體的方法體就是在AsyncTask 類的構(gòu)造方法總中定義的方法體。為了方便觀察,我把這段代碼在粘貼一次:
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); // 執(zhí)行 doInBackground 回調(diào)方法,參數(shù)在mParams的值在executeOnExecutor()中初始化了
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result); // 設置結(jié)果
}
return result;
}
};
看了這么久的代碼,我們總算看到了執(zhí)行任務的方法,也就是我們的重寫方法 doInBackground(mParams) 返回的 Result 是結(jié)果泛型類型(第三個泛型的類型),在上面說過了三個泛型表示的意義;也就是說,到了這一步,我們的異步任務真正的開始執(zhí)行了;我們接著看finally中的代碼,調(diào)用的 postResult(result) 方法,看看這個方法的具體實現(xiàn):
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
在這個方法中使用了一個新的類 AsyncTaskResult,它也是 AsyncTask 的內(nèi)部類,定義如下:
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
回過頭在看 postResult(Result result) 這個方法中的代碼非常簡單,getHandler()方法獲取到我們在構(gòu)造方法中初始化的 mHandler 對象,接著獲取一個 Message 對象并且創(chuàng)建一個 AsyncTaskResult 對象(這個對象包含了AsyncTask 類的本類對象和 doInBackground()方法返回的結(jié)果對象2個參數(shù))作為消息的內(nèi)容,最后將這個消息發(fā)送到目標 mHandler 。上面說過了這個mHandler是InternalHandler,但是沒有貼出具體實現(xiàn)的代碼,那么現(xiàn)在我們就來看一下它到底做了些什么(InternalHandler類是AsyncTask類的內(nèi)部類):
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}
這段代碼我想大家都能看懂吧,最常見的 Handler 寫法,通過判斷 Message 的 what 進行不同的操作(任務執(zhí)行完成或者更新進度)。我們只需要弄清楚 result.mTask 表示的哪一個對象就可以知道調(diào)用的方法是什么了。
在postResult(Result result)方法中,我們知道了 Message 的 obj 字段的值是 AsyncTaskResult 對象,參數(shù)是 this 和 doInBackground()方法返回的結(jié)果對象,很容易知道this表示 AsyncTask 本類對象;在通過 AsyncTaskResult 的構(gòu)造方法我就知道 result.mTask 就是AsyncTask 的本類對象,所以我們就知道了 result.mTask.finish(result.mData[0]) 方法就是AsyncTask 類的 finish(Result result) 方法了;同理result.mTask.onProgressUpdate(result.mData) 方法就是AsyncTask 類的 onProgressUpdate(Progress... values) 方法。
看看AsyncTask 類的 finish(Result result) 方法:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
方法說明:
- 判斷是不是取消了,如果取消了,就回調(diào)
onCancelled()方法(開發(fā)者重寫) - 如果沒有取消就回調(diào)
onPostExecute(Result result)方法(開發(fā)者重寫) - 將任務的執(zhí)行狀態(tài)改變?yōu)?
FINISHED
到此為止,我們發(fā)現(xiàn)的任務執(zhí)行前的準備方法onPreExecute()、任務執(zhí)行方法 doInBackground 以及 取消方法 onCancelled() 和完成方法 onPostExecute() 都成功回調(diào)了;但是我們更新進度的方法 onProgressUpdate() 卻并沒有在哪里有調(diào)用;如果看的比較知仔細的可能已經(jīng)發(fā)現(xiàn)了,我在第一部分簡單使用中說明了:

那么我們看看 publishProgress(Progress... values) 方法:
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
它和 postResult(Result result) 方法是一樣的,發(fā)送一個消息,就不在多說了,回過頭看一下就知道了。
以上就是 AsyncTask 的主要執(zhí)行過程。