轉載請註明出處:http://blog.csdn.net/vnanyesheshou/article/details/73743534
本文已授權微信公衆號 fanfan程序媛 獨家發佈 掃一掃文章底部的二維碼或在微信搜索 fanfan程序媛 即可關注
上一篇主要說了下AsyncTask的基本用法和注意事項。這篇主要從源碼的角度研究下AsyncTask的原理。
先說下AsyncTask類中表示狀態的一個枚舉類,代碼如下:
public enum Status {
PENDING,
RUNNING,
FINISHED,
}
PENDING 表示尚未執行任務。
RUNNING 表示任務正在運行。
FINISHED 表示任務結束。
AsyncTask中有一個Status類型變量mStatus,初始值爲PENDING。
接着分析任務的執行方法,execute代碼如下:
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;
}
第6行:首先判斷mStatus 的值,如果爲PENDING則向下運行,設置mStatus爲RUNNING;否則拋出異常。也就是說每個異步任務只能執行一次,多次運行會拋出異常。
第18行:調用onPreExecute()函數。這是在UI線程中。
第19行:將參數賦值給mWorker.mParams。
第20行: exec.execute(mFuture)。
這裏的mWorker、exec(sDefaultExecutor)、mFuture看的比較模糊。我們看一下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 {
postResultIfNotInvoked(get());
} 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);
}
}
};
}
mWorker是WorkerRunnable類型實例,WorkerRunnable代碼如下:
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
WorkerRunnable類是AsyncTask內部的一個抽象類,它實現了Callable接口,其中參數mParams用來保存傳入的參數。mWorker實現了Callable中的call()方法。Callable類似於Runnable的接口,實現Callable接口和Runnable都是可被其他線程執行的任務。
Callable定義的方法是call,Runnalbe定義的是run。
mWorker 的call方法中設置線程優先級爲後臺級別。然後調用AsyncTask的doInBackground方法(在子線程中)。
mFuture是FutureTask的實例(java.util.concurrent.FutureTask),FutureTask是一個可以中途取消的異步計算類。mFuture實例中,將會調用mWorker做任務,完成後會調用其done方法。
exec是由函數execute(Params…)傳過來的參數sDefaultExecutor。sDefaultExecutor的初始化如下:
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();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
sDefaultExecutor 是SerialExecutor的實例,SerialExecutor實現了Executor接口,該類中有一個任務隊列,任務執行execute,然後 exec.execute(mFuture)會調用到SerialExecutor的execute方法。
第9行 將任務添加到任務隊列中。
第14行 該任務執行完後,調用scheduleNext,執行下一個任務。
第18行 判斷mActive 是否爲null,爲空則調用scheduleNext。這表示任務是一個一個執行(串行)。
scheduleNext函數從任務隊列取出首任務,如果不爲null,則傳入THREAD_POOL_EXECUTOR執行該任務。
多個任務依次調用execute方法。第一個任務入隊,mActive 爲null,執行scheduleNext,從隊列中取出第一個任務,交給線程池去執行。第二個任務入隊,mActive此時不爲空,所以先不執行該任務。之後的各個任務也都添加到隊列中,不會串行執行。前面的任務執行完後,會執行Runnable中的finally代碼塊中的scheduleNext函數,然後從隊列中取出任務,交給線程池執行。
接着看THREAD_POOL_EXECUTOR:
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是新建的一個線程池執行器,用於管理線程的執行。
接着看mFuture。
mFuture的done()方法中,如果任務順利完成,則調用postResultIfNotInvoked(get()),get()方法用來獲取執行任務的結果;如果捕捉到CancellationException則調用postResultIfNotInvoked(null)。
接着看postResultIfNotInvoked
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
private Result postResult(Result result) {
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
postResultIfNotInvoked函數調用postResult函數。
第10行 創建AsyncTaskResult對象,保存異步任務的結果及對應的任務。
第11行 將message發送給Handler進行處理。
看下Handler的代碼:
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:
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
接收到MESSAGE_POST_RESULT消息,調用AsyncTask的finish方法。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
第2行,判斷任務是否取消,如果取消則回調onCancelled(Result)方法。否則調用onPostExecute(Result)方法。
第7行,將任務狀態設置爲FINISHED。
publishProgress
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
通過調用publishProgress來更新任務進度。該方法中先判斷任務是否取消,如果取消則不在處理。否則向Handler發送消息。
Handler接收到MESSAGE_POST_PROGRESS消息後,調用AsyncTask的onProgressUpdate()方法,更新進度。
到此AsyncTask就說的差不多了。AsyncTask是對線程池、Handler的良好封裝,是我們使用更加簡單方便。但是AsyncTask使用也有一定的缺陷,長時間的任務不建議使用AsyncTask。
歡迎掃一掃關注我的微信公衆號,定期推送優質技術文章: