Android AsyncTask 原始碼解析(張鴻洋版)
阿新 • • 發佈:2019-01-30
1、概述
相信大家對AsyncTask都不陌生,對於執行耗時任務,然後更新UI是一把利器,當然也是替代Thread + Handler 的一種方式。如果你對Handler機制還不瞭解,請看:Android 非同步訊息處理機制 讓你深入理解 Looper、Handler、Message三者關係。
2、簡單的例子
相信大家都寫過這樣的程式碼:
[java] view plain copy print?- package com.example.zhy_asynctask_demo01;
- import android.app.Activity;
- import android.app.ProgressDialog;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.util.Log;
- import android.widget.TextView;
- publicclass MainActivity extends Activity
- {
- privatestaticfinal String TAG = “MainActivity”;
- private ProgressDialog mDialog;
- private TextView mTextView;
- @Override
- protected
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mTextView = (TextView) findViewById(R.id.id_tv);
- mDialog = new ProgressDialog(this);
- mDialog.setMax(100);
- mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- mDialog.setCancelable(false);
- new MyAsyncTask().execute();
- }
- privateclass MyAsyncTask extends AsyncTask<Void, Integer, Void>
- {
- @Override
- protectedvoid onPreExecute()
- {
- mDialog.show();
- Log.e(TAG, Thread.currentThread().getName() + ” onPreExecute ”);
- }
- @Override
- protected Void doInBackground(Void… params)
- {
- // 模擬資料的載入,耗時的任務
- for (int i = 0; i < 100; i++)
- {
- try
- {
- Thread.sleep(80);
- } catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- publishProgress(i);
- }
- Log.e(TAG, Thread.currentThread().getName() + ” doInBackground ”);
- returnnull;
- }
- @Override
- protectedvoid onProgressUpdate(Integer… values)
- {
- mDialog.setProgress(values[0]);
- Log.e(TAG, Thread.currentThread().getName() + ” onProgressUpdate ”);
- }
- @Override
- protectedvoid onPostExecute(Void result)
- {
- // 進行資料載入完成後的UI操作
- mDialog.dismiss();
- mTextView.setText(”LOAD DATA SUCCESS ”);
- Log.e(TAG, Thread.currentThread().getName() + ” onPostExecute ”);
- }
- }
- }
package com.example.zhy_asynctask_demo01;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends Activity
{
private static final String TAG = "MainActivity";
private ProgressDialog mDialog;
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.id_tv);
mDialog = new ProgressDialog(this);
mDialog.setMax(100);
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setCancelable(false);
new MyAsyncTask().execute();
}
private class MyAsyncTask extends AsyncTask<Void, Integer, Void>
{
@Override
protected void onPreExecute()
{
mDialog.show();
Log.e(TAG, Thread.currentThread().getName() + " onPreExecute ");
}
@Override
protected Void doInBackground(Void... params)
{
// 模擬資料的載入,耗時的任務
for (int i = 0; i < 100; i++)
{
try
{
Thread.sleep(80);
} catch (InterruptedException e)
{
e.printStackTrace();
}
publishProgress(i);
}
Log.e(TAG, Thread.currentThread().getName() + " doInBackground ");
return null;
}
@Override
protected void onProgressUpdate(Integer... values)
{
mDialog.setProgress(values[0]);
Log.e(TAG, Thread.currentThread().getName() + " onProgressUpdate ");
}
@Override
protected void onPostExecute(Void result)
{
// 進行資料載入完成後的UI操作
mDialog.dismiss();
mTextView.setText("LOAD DATA SUCCESS ");
Log.e(TAG, Thread.currentThread().getName() + " onPostExecute ");
}
}
}
進入某個Activity,Activity中需要的資料來自於網路或者其它耗時操作,可以在AsyncTask中onPreExecute完成一些準備操作,比如上例中顯示進度對話方塊;然後在doInBackground完成耗時操作,在進行耗時操作時還能不時的通過publishProgress給onProgressUpdate中傳遞引數,然後在onProgressUpdate中可以進行UI操作,比如上例更新進度條的進度;當耗時任務執行完成後,最後在onPostExecute進行設定控制元件資料更新UI等操作,例如隱藏進度對話方塊。
效果圖:
3、原始碼解析
注:本篇原始碼分析基於Andorid-17,因為和3.0之前版本變動較大,有必要標出。那麼大家一定好奇,AsyncTask在Android中是如何實現的,下面進行原始碼分析:從我們的執行非同步任務的起點開始,進入execute方法:
- publicfinal AsyncTask<Params, Progress, Result> execute(Params… params) {
- return executeOnExecutor(sDefaultExecutor, params);
- }
- publicfinal AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
- Params… params) {
- if (mStatus != Status.PENDING) {
- switch (mStatus) {
- case RUNNING:
- thrownew IllegalStateException(“Cannot execute task:”
- + ” the task is already running.”);
- case FINISHED:
- thrownew 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);
- returnthis;
- }
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;
}
18行:設定當前AsyncTask的狀態為RUNNING,上面的switch也可以看出,每個非同步任務在完成前只能執行一次。20行:執行了onPreExecute(),當前依然在UI執行緒,所以我們可以在其中做一些準備工作。
22行:將我們傳入的引數賦值給了mWorker.mParams
23行:exec.execute(mFuture)
相信大家對22行出現的mWorker,以及23行出現的mFuture都會有些困惑。
mWorker找到這個類:
- privatestaticabstractclass WorkerRunnable<Params, Result> implements Callable<Result> {
- Params[] mParams;
- }
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
可以看到是Callable的子類,且包含一個mParams用於儲存我們傳入的引數,下面看初始化mWorker的程式碼:
[java] view plain copy print?
- public AsyncTask() {
- mWorker = new WorkerRunnable<Params, Result>() {
- public Result call() throws Exception {
- mTaskInvoked.set(true);
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- //noinspection unchecked
- return postResult(doInBackground(mParams));
- }
- };
- //….
- }
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
//….
}
可以看到mWorker在構造方法中完成了初始化,並且因為是一個抽象類,在這裡new了一個實現類,實現了call方法,call方法中設定mTaskInvoked=true,且最終呼叫doInBackground(mParams)方法,並返回Result值作為引數給postResult方法.可以看到我們的doInBackground出現了,下面繼續看:
[java] view plain copy print?
- private Result postResult(Result result) {
- @SuppressWarnings(“unchecked”)
- Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
- new AsyncTaskResult<Result>(this, result));
- message.sendToTarget();
- return result;
- }
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
可以看到postResult中出現了我們熟悉的非同步訊息機制,傳遞了一個訊息message, message.what為MESSAGE_POST_RESULT;message.object= new AsyncTaskResult(this,result);
[java] view plain copy print?
- privatestaticclass AsyncTaskResult<Data> {
- final AsyncTask mTask;
- final Data[] mData;
- AsyncTaskResult(AsyncTask task, Data… data) {
- mTask = task;
- mData = data;
- }
- }
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
AsyncTaskResult就是一個簡單的攜帶引數的物件。
看到這,我相信大家肯定會想到,在某處肯定存在一個sHandler,且複寫了其handleMessage方法等待訊息的傳入,以及訊息的處理。
- privatestaticfinal InternalHandler sHandler = new InternalHandler();
- privatestaticclass InternalHandler extends Handler {
- @SuppressWarnings({“unchecked”, “RawUseOfParameterizedType”})
- @Override
- publicvoid 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 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;
}
}
}
哈哈,出現了我們的handleMessage,可以看到,在接收到MESSAGE_POST_RESULT訊息時,執行了result.mTask.finish(result.mData[0]);其實就是我們的AsyncTask.this.finish(result),於是看finish方法[java] view plain copy print?
- privatevoid finish(Result result) {
- if (isCancelled()) {
- onCancelled(result);
- } else {
- onPostExecute(result);
- }
- mStatus = Status.FINISHED;
- }
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
可以看到,如果我們呼叫了cancel()則執行onCancelled回撥;正常執行的情況下呼叫我們的onPostExecute(result);主要這裡的呼叫是在handler的handleMessage中,所以是在UI執行緒中。如果你對非同步訊息機制不理解請看:Android 非同步訊息處理機制 讓你深入理解 Looper、Handler、Message三者關係
最後將狀態置為FINISHED。
mWoker看完了,應該到我們的mFuture了,依然實在構造方法中完成mFuture的初始化,將mWorker作為引數,複寫了其done方法。
- public AsyncTask() {
- …
- mFuture = new FutureTask<Result>(mWorker) {
- @Override
- protectedvoid done() {
- try {
- postResultIfNotInvoked(get());
- } catch (InterruptedException e) {
- android.util.Log.w(LOG_TAG, e);
- } catch (ExecutionException e) {
- thrownew RuntimeException(“An error occured while executing doInBackground()”,
- e.getCause());
- } catch (CancellationException e) {
- postResultIfNotInvoked(null);
- }
- }
- };
- }
public AsyncTask() {
...
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);
}
}
};
}
16行:任務執行結束會呼叫:postResultIfNotInvoked(get());get()表示獲取mWorker的call的返回值,即Result.然後看postResultIfNotInvoked方法[java] view plain copy print?- privatevoid postResultIfNotInvoked(Result result) {
- finalboolean wasTaskInvoked = mTaskInvoked.get();
- if (!wasTaskInvoked) {
- postResult(result);
- }
- }
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
如果mTaskInvoked不為true,則執行postResult;但是在mWorker初始化時就已經將mTaskInvoked為true,所以一般這個postResult執行不到。好了,到了這裡,已經介紹完了execute方法中出現了mWorker和mFurture,不過這裡一直是初始化這兩個物件的程式碼,並沒有真正的執行。下面我們看真正呼叫執行的地方。
execute方法中的:
還記得上面的execute中的23行:exec.execute(mFuture)
exec為executeOnExecutor(sDefaultExecutor, params)中的sDefaultExecutor
[java] view plain copy print?
- privatestaticvolatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
- publicstaticfinal Executor SERIAL_EXECUTOR = new SerialExecutor();
- privatestaticclass SerialExecutor implements Executor {
- final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
- Runnable mActive;
- publicsynchronizedvoid execute(final Runnable r) {
- mTasks.offer(new Runnable() {
- publicvoid run() {
- try {
- r.run();
- } finally {
- scheduleNext();
- }
- }
- });
- if (mActive == null) {
- scheduleNext();
- }
- }
- protectedsynchronizedvoid scheduleNext() {
- if ((mActive = mTasks.poll()) != null) {
- THREAD_POOL_EXECUTOR.execute(mActive);
- }
- }
- }
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);
}
}
}
可以看到sDefaultExecutor其實為SerialExecutor的一個例項,其內部維持一個任務佇列;直接看其execute(Runnable runnable)方法,將runnable放入mTasks隊尾;16-17行:判斷當前mActive是否為空,為空則呼叫scheduleNext方法
20行:scheduleNext,則直接取出任務佇列中的隊首任務,如果不為null則傳入THREAD_POOL_EXECUTOR進行執行。
下面看THREAD_POOL_EXECUTOR為何方神聖:
[java] view plain copy print?
- publicstaticfinal Executor THREAD_POOL_EXECUTOR
- =new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
- TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
public static final Executor THREAD_POOL_EXECUTOR
=new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看到就是一個自己設定引數的執行緒池,引數為:[java] view plain copy print?- privatestaticfinalint CORE_POOL_SIZE = 5;
- privatestaticfinalint MAXIMUM_POOL_SIZE = 128;
- privatestaticfinalint KEEP_ALIVE = 1;
- privatestaticfinal ThreadFactory sThreadFactory = new ThreadFactory() {
- privatefinal AtomicInteger mCount = new AtomicInteger(1);
- public Thread newThread(Runnable r) {
- returnnew Thread(r, “AsyncTask #” + mCount.getAndIncrement());
- }
- };
- privatestaticfinal BlockingQueue<Runnable> sPoolWorkQueue =
- new LinkedBlockingQueue<Runnable>(10);
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);
看到這裡,大家可能會認為,背後原來有一個執行緒池,且最大支援128的執行緒併發,加上長度為10的阻塞佇列,可能會覺得就是在快速呼叫138個以內的AsyncTask子類的execute方法不會出現問題,而大於138則會丟擲異常。
其實不是這樣的,我們再仔細看一下程式碼,回顧一下sDefaultExecutor,真正在execute()中呼叫的為sDefaultExecutor.execute:
[java] view plain copy print?
- privatestaticclass SerialExecutor implements Executor {
- final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
- Runnable mActive;
- publicsynchronizedvoid execute(final Runnable r) {
- mTasks.offer(new Runnable() {
- publicvoid run() {
- try {
- r.run();
- } finally {
- scheduleNext();
- }
- }
- });
- if (mActive == null) {
- scheduleNext();
- }
- }
- protectedsynchronizedvoid scheduleNext() {
- if ((mActive = mTasks.poll()) != null) {
- THREAD_POOL_EXECUTOR.execute(mActive);
- }
- }
- }
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);
}
}
}
可以看到,如果此時有10個任務同時呼叫execute(s synchronized)方法,第一個任務入隊,然後在mActive = mTasks.poll()) != null被取出,並且賦值給mActivte,然後交給執行緒池去執行。然後第二個任務入隊,但是此時mActive並不為null,並不會執行scheduleNext();所以如果第一個任務比較慢,10個任務都會進入佇列等待;真正執行下一個任務的時機是,執行緒池執行完成第一個任務以後,呼叫Runnable中的finally程式碼塊中的scheduleNext,所以雖然內部有一個執行緒池,其實呼叫的過程還是線性的。一個接著一個的執行,相當於單執行緒。
4、總結
到此原始碼解釋完畢,由於程式碼跨度比較大,我們再回顧一下:
[java] view plain copy print?- publicfinal AsyncTask<Params, Progress, Result> execute(Params… params) {
- return executeOnExecutor(sDefaultExecutor, params);
- }
- publicfinal AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
- Params… params) {
- if (mStatus != Status.PENDING) {
- switch (mStatus) {
- case RUNNING:
- thrownew IllegalStateException(“Cannot execute task:”
- + ” the task is already running.”);
- case FINISHED:
-