Android-AsyncTask源碼分析
AsyncTask非同步任務類,允許在UI線程中進行後台操作和發布結果到UI線程中,一般使用多操作中,這個類的基本用法可以參照博主寫的另一邊博文http://blog.csdn.net/nzsdyun123/article/details/22215589這裡有講述AsyncTask的基本用法,今天我也按照上篇分析Handler機制那樣帶領大家來分析下AsyncTask的流程。
我們一般是這樣來開始啟動AsyncTask的:
MyAsyncTask myAsyncTask = new MyAsyncTask();
myAsyncTask.execute(path);
這裡MyAysncTask是AysncTask的子類,這裡我們使用AsyncTask的時候也是一般繼承AysncTask類,重寫其方法,我們查看AysncTask的源碼發現:
/**
*
AsyncTask enables proper and easy use of the UI thread. This class allows to
* perform background operations and publish results on the UI thread without
* having to manipulate threads and/or handlers.
*
*
AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
* and does not constitute a generic threading framework. AsyncTasks should ideally be
* used for short operations (a few seconds at the most.) If you need to keep threads
* running for long periods of time, it is highly recommended you use the various APIs
* provided by the java.util.concurrent pacakge such as {@link Executor},
* {@link ThreadPoolExecutor} and {@link FutureTask}.
AsyncTask是後台UI線程,通過發布結果到UI線程中,同時這裡也給我們介紹了AsyncTask被設計成Thread和Handler的一個助手類,適用於短時的線程操作,長時的線程操作被推薦適用線程池ThreadPoolExecutor來解決,及其他的一些基礎用法等,從這裡的簡介中,提到AsyncTask被設計成Thread和Handler的一個助手類?我們這時就要想AsyncTask是不是對Thread+Handler的一個封裝?答案是這樣嗎?我們帶著疑問來分析:
當我們調用myAsyncTask.execute(path);這語句時,這時AsyncTask就開始正式工作了。我們來進入源碼分析這句:
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
這裡函數被設計成接收三個泛型資料類型的類,同時參數被設計成可變參數,可以根據實際需求動態傳入參數的個數。我們接著看跟蹤 return executeOnExecutor(sDefaultExecutor, params);
public final AsyncTask executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {//尚未建立AsyncTask
switch (mStatus) {
case RUNNING://有AsyncTask正在後台運行,拋出異常
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED://有AsyncTask任務已完成
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;
}
從上述分析可以知道當前UI線程的AsyncTask對象不能多次調用execute方法,關鍵的是我們看這幾句
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
追蹤onPreExecute();可以發現這是一個空實現方法:
/**
* Runs on the UI thread before {@link #doInBackground}.
*
* @see #onPostExecute
* @see #doInBackground
*/
protected void onPreExecute() {
}
子類可以重寫它,運行在UI線程,在doInBackground方法之前,從這裡我們可以知道,既然onPreExecute函數運行在UI線程中,所以我們可以在這做些資源的初始化的工作。接著來分析 mWorker.mParams = params;這句是將參數賦值給mWorker對象的參數。所以我們追蹤mWorker對象發現:
private final WorkerRunnable mWorker;
private final FutureTask mFuture;
它是AsyncTask的類類型對象,那WorkerRunnable到底是什麼呢?追蹤源碼可知:
private static abstract class WorkerRunnable implements Callable {
Params[] mParams;
}
它是一個抽象類別,實現了Callable回調介面,用於從不同的線程來擷取結果Result,OK,我們接著分析:
exec.execute(mFuture);從executeOnExecutor函式宣告中可以看出exec是Executor的對象,Excutor?哇,這不就是線程池的運用嘛(線程池知識這裡不講解),這裡簡單講下Excutor,Excutor是一個介面,此介面提供一種將任務提交與每個任務將如何啟動並執行機制(包括線程使用的細節、調度等)分離開來的方法。簡單講就是方便線程的建立和使用。那麼exec.execute(mFuture);就是執行線程,那這個mFuture肯定是一個Runnable或者實現Runnable介面的類,追蹤mFuture:
private final FutureTask mFuture;
FutureTask?這又是什麼呢?我們查看JDK協助文檔可知:
public class FutureTask
extends Object
implements RunnableFuture
它是繼承了Object對象,實現RunnableFuture介面的類,當然RunnableFuture實現了Runnable介面,果不其然,由JDK可知
FutureTask是一個可取消的非同步計算。利用開始和取消計算的方法、查詢計算是否完成的方法和擷取計算結果的方法。簡單來講就是擷取提供一些方法來開始和取消線程,同時可以擷取線程運行後的結果。那麼FutureTask和WorkerRunnable對象又是什麼時候開始建立的呢?追蹤可以發現它們是在我們建立AsyncTask對象時就給我們建立好了:
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable() {//建立WorkerRunnable,並實現Callable介面方法call
public Result call() throws Exception {
mTaskInvoked.set(true);//設定標誌值
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//設定線程優先順序
//noinspection unchecked
return postResult(doInBackground(mParams));//根據外部傳入的參數調用doInBackground方法,並將結果傳給postResult函數
}
};
mFuture = new FutureTask(mWorker) {
//建立FutureTask對象,重寫done方法
@Override
protected void done() {
try {
postResultIfNotInvoked(get());//等到線程執行完成,通過get方法擷取線程運行後的結果,傳給postResultIfNotInvoked方法
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
原來這兩個對象在AsyncTask類建立的時候就給預先建立好了,前面說到WorkerRunnable是一個實現了Runnable介面的類,當系統執行到exec.execute(mFuture);這句時,這時就會執行線程裡的WorkerRunnable的方法,這裡們可以看到,AsyncTask的設計者巧妙的使用回調,將需要線上程中啟動並執行語句又交到了我們開發應用者手上,我們查看doInBackground(mParams)就可以知道:
protected abstract Result doInBackground(Params... params);
這是一個抽象的方法,我們子類可以實現它,當然這些語句會運行在另一個線程中,Ok這時我們查看postResult和postResultIfNotInvoked方法:
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
postResultIfNotInvoked方法最後也是調用postResult方法:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
從這裡可以看出,向sHandler所在的線程發送一個訊息,並將線程運行後的結果回傳過去,ok,這裡我們分析sHandler對象的類:
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;
}
}
}
從上面可以知道,此Handler類接收兩個訊息:MESSAGE_POST_RESULT線程執行完畢後訊息,MESSAGE_POST_PROGRESS進度更新訊息
result.mTask.finish(result.mData[0]);
我們從這句語句找到finish方法:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
要麼是調用 */
@SuppressWarnings({"UnusedParameters"})
protected void onCancelled(Result result) {
onCancelled();
}
onCancelled來取消AysncTask,不然就是等待線程運行完成後,提交給onPostExecute(result);方法處理:
@SuppressWarnings({"UnusedDeclaration"})
protected void onPostExecute(Result result) {
}
所以,我們可以在子類中重寫onPostExecute這個方法時,擷取其結果,而MESSAGE_POST_PROGRESS訊息是將結果交於onProgressUpdate(result.mData);處理:
@SuppressWarnings({"UnusedDeclaration"})
protected void onProgressUpdate(Progress... values) {
}
這裡一般是我們重寫時擷取進度來進行進度條更新的,那這個訊息MESSAGE_POST_PROGRESS又從哪裡向handler發送的呢?我們繼續追查:
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult(this, values)).sendToTarget();
}
}
在這個方法裡發送的,這就我們可以解釋的同,為什麼我們調用
publishProgress的時候,可以在onProgressUpdate接收結果並更新UI,publishProgress是通過handler向建立AsyncTask所在的線程中發送訊息並將結果回傳過去的。到目前為止,AsyncTask的源碼分析就分析的差不多了,這也驗證了我們剛開始的猜想,AsyncTask是對Thread+Handler的封裝,當然這裡不是直接使用Thread的,而已使用靜態線程池來進行的,這個查看AsyncTask的各個屬性聲明就可以知道,當然這也帶來了一些限制,那就是線程數不能建立太多。