AsyncTask是Android提供的一個異步加載任務的工具類,AsyncTask源碼其實不是特別複雜,不過由於在Android3.0後進行了修改,導致AsyncTask的使用還是很容易入坑的。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return 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;
}
AsyncTask默認的execute方法會調用executeOnExecutor,傳入sDefaultExecutor。
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);
}
}
}
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
默認的SERIAL_EXECUTOR是用來對任務進行排隊的,真正的執行在scheduleNext()
中。
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
可以看到THREAD_POOL_EXECUTOR纔是真正用來執行任務的線程池。之所以這麼做,是Google在3.0之後讓AsyncTask的任務串行化來避免一些並行錯誤。不過想要並行也是可以的,調用executeOnExecutor(Executor exec,Params... params)
,傳入自己配置的線程池來執行併發任務。
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
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>(10);
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看到THREAD_POOL_EXECUTOR是public的,因此也可以選擇THREAD_POOL_EXECUTOR來執行併發。(默認串行執行的情況下實際上這種配置意義就不大了,在3.0之前是不支持串行執行的)
流程分析
先看AsyncTask的構造方法。
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
final Result result = get();
postResultIfNotInvoked(result);
} 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);
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
}
};
}
AsyncTask在構造方法中創建了WorkerRunnable和FutureTask,WorkerRunnable是實現了Callable的類,內部保存Params。
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
因此AsyncTask是採用FutureTask來進行異步計算的。FutureTask是一個可以返回異步結果、取消操作等的Future接口的實現,同時FutureTask又實現了Runnable,因此也直接在線程中運行。
在WorkerRunnable的call方法中最後會執行postResult(doInBackground(mParams));
,可以看到doInBackground確實是在子線程執行的。
private Result postResult(Result result) {
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
postResult將計算結果封裝成AsyncTaskResult發給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;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
sHandler是一個靜態常量,這也說明了爲了切換到主線程第一次AsyncTask必須在主線程創建的原因。InternalHandler在handleMessage的時候會消息類型來判斷是finish還是onProgressUpdate。
斷斷散散的AsyncTask分析就結束了,但是感覺還沒有理清頭緒,現在從execute(Params… params)具體分析一下執行流程。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
execute調用了executeOnExecutor並傳入了默認的sDefaultExecutor,前面已經說過這是一個用來排隊的線程池。
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;
}
executeOnExecutor一進來會判斷mStatus的狀態(mStatus初始化爲PENDING狀態)
private volatile Status mStatus = Status.PENDING;
如果mStatus不爲Status.PENDING則會拋出異常,這也是同一個AsyncTask只能執行一次execute的原因。如果是第一執行,首先將mStatus設置爲Status.RUNNING,然後回調onPreExecute();
,因此onPreExecute是在任務執行前在主線程回調的。
接着講params設置到mWorker中,然後調用exec.execute(mFuture);
,我們來看一下exec,也就是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);
}
}
}
exec.execute(mFuture);
會將創建一個新的Runnable放到自己的mTasks中。接着判斷mActive是否爲空,第一次進來肯定爲空,接着執行scheduleNext();
方法。
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
scheduleNext方法將SerialExecutor中mTasks的Runnable彈出一個並賦值給mActive(這樣再次調用execute方法就不會進入這個判斷語句中了),然後將Runnable交給真正的線程池THREAD_POOL_EXECUTOR來執行任務。THREAD_POOL_EXECUTOR.execute(mActive)
。
剛纔也說了第二次調用execute方法不會走到判空語句,就不會執行scheduleNext方法,那怎麼實現串行?現在我們來看SerialExecutor的execute方法。
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
Runnable r 是我們傳進去的mFuture,在mFuture的run()方法執行完後,在try{}finally{scheduleNext();}
finally中會執行scheduleNext()
,再從mTasks中彈出一個Runnable交給THREAD_POOL_EXECUTOR執行。通過這個邏輯實現了串行執行。
Runnable的run()方法中調用mFuture的run()方法,mFuture的run()方法會調用mWorker的call方法。我們看看mWorker的call做了啥。
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return postResult(doInBackground(mParams));
}
};
首先將任務調度標識mTaskInvoked設爲true,表示任務被調用。接着設置進程優先級。最後調用doInBackground(mParams)
執行後臺任務,並通過postResult()
方法將doInBackground返回結果傳到主線程。
private Result postResult(Result result) {
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
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;
}
}
}
InternalHandler判斷傳過來的Message,如果what是MESSAGE_POST_RESULT,代表是doInBackground的返回結果,並調用finish()
。如果what是MESSAGE_POST_PROGRESS,代表是開發者調用的publishProgress
來更新進度,並回調onProgressUpdate(Progress… values)。
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
至此AsyncTask怎麼實現串行異步任務的分析就結束了,至於並行則是直接把mFuture交給executeOnExecutor(Executor exec,Params... params)
傳進來的自定義線程池exec去執行,來實現並行執行。
最後再提一下AsyncTask的取消操作。
public final boolean cancel(boolean mayInterruptIfRunning) {
return mFuture.cancel(mayInterruptIfRunning);
}
AsyncTask的cancel直接調用mFuture的cancel方法。mFuture在調用了cancel後,會回調mFuture的done()方法。
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
final Result result = get();
postResultIfNotInvoked(result);
} 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);
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
}
};
done()方法中get()會拋出CancellationException異常,然後執行postResultIfNotInvoked(null);
。