前言
AsyncTask是很多人接觸的第一個用來完成異步任務(wù)的東西。相信大家都知道它的使用方法夜郁,今天我們來看一下他的源碼什燕,來弄明白其中的原理。
源碼解析
首先先從入口開始竞端,execute方法會轉(zhuǎn)入executeOnExecutor方法屎即。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
//sDefaultExecutor是一個SerialExecutor對象,關(guān)于他的介紹放在了文章末尾
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;
}
private volatile Status mStatus = Status.PENDING;
AsyncTask對象的初始狀態(tài)為PENDING,之后我們會介紹到技俐,當任務(wù)被取消乘陪,或者onPostExecute()執(zhí)行完之后,狀態(tài)會被設(shè)置為FINISHED虽另。
那么我們可以得到一個對開發(fā)有用的信息:
每個AsyncTask對象只能被execute一次暂刘,第二次被執(zhí)行時會拋出異常。
可以看到捂刺,我們經(jīng)常要重寫的onPreExecute()方法在這里被調(diào)用谣拣。之后就在線程池里執(zhí)行了這個任務(wù),那么這個mFuture是在哪初始化的呢族展?顯然只能是在構(gòu)造方法里森缠,我們?nèi)タ匆幌?/p>
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return 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);
}
}
};
}
這里對FutureTask做一個簡單的介紹,F(xiàn)utureTask實現(xiàn)了Runnable接口仪缸,所以可以在線程池中被執(zhí)行贵涵。在FutureTask的Run方法中,實際上被執(zhí)行的是傳入的Callable的call方法恰画,此處也就是指mWork的call方法宾茂,然后會執(zhí)行FutureTask的done方法。
經(jīng)過上面的介紹我們可以直到拴还,call和done方法都運行在線程池中跨晴,doInBackground方法在call中被執(zhí)行,所以doInBackground方法可以進行一些耗時操作片林,如網(wǎng)絡(luò)請求和數(shù)據(jù)庫操作端盆。
可以看到,doInBackground方法的返回值被傳入了postResult方法费封,跟蹤進來:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
這里使用了Message焕妙!看到這里我想大家就應(yīng)該明白了,AsyncTask中是使用Handler來實現(xiàn)線程的切換的弓摘。代碼中是使用obtainMessage方法來獲取Message對象的焚鹊,這樣有什么好處呢?
obtainMessage()是從消息池中回收一個Message韧献,這樣比使用New Message()來創(chuàng)建Message對象更節(jié)省資源寺旺。
既然已經(jīng)使用sendToTarget方法將message發(fā)送,那么我們?nèi)ゲ榭磳?yīng)的handler:
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;
}
}
}
當doInBackground方法執(zhí)行完之后势决,進入MESSAGE_POST_RESULT對應(yīng)的分支阻塑,那么MESSAGE_POST_PROGRESS呢?回想一下AsyncTask中需要在主線程中運行的代碼還有什么果复?
相信大家已經(jīng)想到了陈莽,AsyncTask中需要在主線程運行的方法有兩個:
- onPostExecute(),獲取數(shù)據(jù)之后進行UI操作
- onProgressUpdate(),在耗時操作的時候更新進度條
首先我們來看finish方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
如果這個任務(wù)已經(jīng)被取消了走搁,那么就不會調(diào)用onPostExecute()独柑,否則將會調(diào)用它。最后會將該AsyncTask對象的狀態(tài)設(shè)置為FINISHED私植。這樣一套流程就走完了~ 下面我們看一看關(guān)于更新進度條的部分忌栅。
我們知道,當在doInBackground()想要更新進度條的時候曲稼,應(yīng)該調(diào)用publishProgress()
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
然后我們再去看一看Handler索绪。
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;
}
}
}
可以看到,onProgressUpdate方法會被調(diào)用贫悄。
下面我們來介紹默認的線程池瑞驱。
/**
*用來將任務(wù)排隊
*/
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);
}
}
}
mTask是一個隊列,相信大家也能看出來窄坦,SerialExecutor是用來將任務(wù)排隊的唤反,當某一個AsyncTask類的多個對象同時調(diào)用execute()時,任務(wù)會被順序執(zhí)行鸭津,我們寫個demo測試一下彤侍。
public class SecondActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TestAsyncTask testAsyncTask = new TestAsyncTask();
testAsyncTask.execute();
}
});
}
private class TestAsyncTask extends AsyncTask<Object,Integer,String>{
@Override
protected String doInBackground(Object... params) {
Log.d("test","doInBackground");
try{
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String s) {
Log.d("test","onPostExecute");
}
}
}
然后我連續(xù)快速地點擊3下button,打印結(jié)果如下:
05-10 14:12:11.623 1871-3036/com.gustiness.secondtrain D/test: doInBackground
05-10 14:12:11.623 1871-1871/com.gustiness.secondtrain D/test: onPostExecute
05-10 14:12:14.619 1871-3036/com.gustiness.secondtrain D/test: doInBackground
05-10 14:12:14.619 1871-1871/com.gustiness.secondtrain D/test: onPostExecute
05-10 14:12:17.619 1871-3036/com.gustiness.secondtrain D/test: doInBackground
05-10 14:12:17.619 1871-1871/com.gustiness.secondtrain D/test: onPostExecute
可以發(fā)現(xiàn)逆趋,當?shù)谝粋€任務(wù)執(zhí)行完之后拥刻,下一個任務(wù)才會被執(zhí)行,這也就驗證了我們剛才的結(jié)論父泳。
我們稍微修改一下代碼,驗證文章開頭出的結(jié)論:每個AsyncTask對象只能被execute一次吴汪,第二次被執(zhí)行時會拋出異常惠窄。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Button button = (Button) findViewById(R.id.button);
final TestAsyncTask testAsyncTask = new TestAsyncTask();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
testAsyncTask.execute();
}
});
}
連續(xù)點擊兩次button,程序崩潰漾橙,報錯信息為:
05-10 14:18:19.495 8499-8499/com.gustiness.secondtrain E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.IllegalStateException: Cannot execute task: the task is already running.
at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:575)
at android.os.AsyncTask.execute(AsyncTask.java:534)
at com.gustiness.secondtrain.SecondActivity$1.onClick(SecondActivity.java:25)
等AsyncTask執(zhí)行完成之后再點擊button杆融,程序崩潰,報錯信息為:
05-10 14:21:06.171 10645-10645/com.gustiness.secondtrain E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)
at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:578)
at android.os.AsyncTask.execute(AsyncTask.java:534)
at com.gustiness.secondtrain.SecondActivity$1.onClick(SecondActivity.java:25)
驗證了文章開頭處的結(jié)論:每個AsyncTask對象只能被執(zhí)行一次霜运。
到這里我們也就將AsyncTask的源碼分析完了脾歇,是不是覺得理解的更深入一些了呢?平時養(yǎng)成看源碼的習慣淘捡,會成長的更快藕各,一起加油~