在上一篇AsyncTask源碼分析中爲大家做了一些基礎知識的鋪墊,這篇就爲大家真正解析一下AsyncTask源碼:
首先爲大家介紹一些AsyncTask的一些特性:
1、AsyncTask在3.0版本以後默認是串行的
2、AsyncTask不能在非UI線程中創建
3、AsyncTask任務數量上限是128個
4、AsyncTask只適合短時間幾秒的耗時操作,不適合長時間的
耗時操作,原因是AsyncTask默認是串行的,如果你一個操作執行幾分鐘,那麼其他的任務就根本沒有辦法執行
5、每個AsyncTask創建一次只能使用一次
首先大家看一下:
/**
* 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);
}
}
};
}
這是AsyncTask的構造方法,在上面的註釋中我們看到AsyncTask必須在UI線程中創建,卻沒有說爲什麼。只是初始化了兩個對象mWorker,mFuture.
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
mWorker實際上是一個實現了Callable接口的類罷了,mFuture也不過是一個FutureTask類。暫時沒有發現什麼用那我們接着往下看:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
當你執行一個任務必然會調用execute方法,那這個方法最終調用的是executeOnExecutor(sDefaultExecutor, params)
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;
}
看到這裏大家一定會看到一個熟悉的方法,onPreExecute(),這個方法經常用來做一些提前的操作,這裏大家明白爲什麼可以提前操作了,因爲它允許在主線程裏。這裏也解釋了爲什麼AsyncTask創建一次只能用一次,因爲AsyncTask是有狀態的,運行之後的狀態爲Running就會報錯,只有狀態爲Pending的時候才能繼續運行下去。params是傳進來的參數,sDefultExecutor是什麼呢?
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
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);
}
}
}
這個sDefaultExector這個方法裏面所有的邏輯操作都是在子線程中執行的,並且是串行的,這也是爲什麼AsyncTask默認是串行執行的原因所在。我來分析一下這個串行執行的奧祕。
1、FutueTask對象通過offer()方法添加進ArrayQueue數組隊列中
2、mActivie == null
3、scheduleNext方法中
4、通過poll()方法取出,賦給mActivie,通過線程池ThreadPoolExecutor去執行
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
5、執行FutureTask裏面的run()方法裏面的內容,其實最終執行的是Callable()接口裏面call()方法裏面的內容,就是這裏傳入的mWorker對象裏面call()方法裏面的內容
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);
}
};
大家驚訝的在這裏發現了我們熟悉的doInBackgroud(mParams)方法,所以doInBackgroud()內容才能在後臺操作,因爲這個方法是在子線程中執行的,接着講執行的結果返回了出去,調用了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;
}
看到postResult方法裏面的內容,大家驚訝的發現了Handler的身影,我們仔細看一下getHandler()方法的源代碼:
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
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;
}
}
}
大家此時突然發現這個獲得的Handler用的是主線程的Looper,這下大家明白爲什麼AsyncTask方法必須在主線程中創建了吧。在handleMessage方法裏面我們看到有兩種狀態一種是MESSAGE_POST_PROGRESS,調用的是更新進度的方法,爲什麼能夠直接更新UI,其實就是利用了Handler進行了線程的切換。還有另外一種狀態是MESSAGE_POST_RESULT,大家看看這個狀態最終調用了finish()
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
大家又看到了onPostExecte這個方法,現在大家對AsyncTask的執行過程有了基本的瞭解,我們回頭來解析完AsyncTask串行的祕密。
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);
}
}
}
調用完FutureTask對象的run()方法之後,谷歌的工程師在這裏做了一個絕妙的處理,利用了Java當中捕獲異常當中的finally絕對會執行的特性,在finally中又再次調用了sheduNext方法,形成了一個如果ArrayQueue這個方法中如果有消息就絕對會執行完成的變異遞歸,如果沒有了,那麼mActive又會立刻爲null,一旦mActive爲null,又會再次走剛剛那套流程。但無論如果,每次都只有一個對象被執行。這就是AsyncTask串行的祕密。
另外爲大家講述一些AsyncTask常用的API:
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
其實這個就是調用了mFuture的cancle()方法,我們經常在一個Activity銷燬的時候調用這個方法,免得消息沒有處理完,AsyncTask因爲無法得到回收。造成內存泄漏
public static void setDefaultExecutor(Executor exec) {
sDefaultExecutor = exec;
}
其實這邊就是剛纔講的設置默認的Executor,通過設置這個可以將AsyncTask變成併發的。