android_AsyncTask的源碼解析

AsyncTask的相關(guān)結(jié)論

下面是AsyncTask的相關(guān)結(jié)論,相關(guān)結(jié)論都會(huì)在下面的源碼分析中一一印證。

  1. onPreExecute()是在異步任務(wù)執(zhí)行之前調(diào)用的,它是在主線程中運(yùn)行。
  2. doInBackground()是在子線程中運(yùn)行,該方法執(zhí)行的耗時(shí)的異步任務(wù)。
  3. onPostExecute(Result result)是執(zhí)行完doInBackground之后被調(diào)用,參數(shù)result就是doInBackground計(jì)算的結(jié)果。
  4. 1,2,3以上3個(gè)方法不用手動(dòng)調(diào)用,它們的調(diào)用都是AsyncTask自己去調(diào)用的。
  5. onProgressUpdate(Progress...values)在UI線程中執(zhí)行,用于時(shí)時(shí)的更新UI,以進(jìn)度條的方式,增加用戶體驗(yàn)。
  6. protected final void publishProgress(Progress... values) 該方法一般會(huì)在doInBackground中執(zhí)行,將計(jì)算的數(shù)據(jù)時(shí)時(shí)通過(guò)該方法傳遞給onProgressUpdate方法。該方法是final類型的。
  7. 異步任務(wù)就是能執(zhí)行耗時(shí)耗時(shí)操作,并且將操作結(jié)果通知到UI線程中,完成此操作就需要使用到Handler消息機(jī)制,在AsyncTask中是通過(guò)InternalHandler去實(shí)現(xiàn)的。
  8. AsyncTask通過(guò)線程池去維護(hù)多個(gè)異步任務(wù)的創(chuàng)建和運(yùn)行。
  9. AsyncTask實(shí)例需要在主線程中去實(shí)例化,因?yàn)閜ostExecute是AsyncTask的方法,AsyncTask若是在子線程中運(yùn)行,那么該方法也是在非UI線程調(diào)用,那么達(dá)不到刷新UI的效果了。
  10. AsyncTask#execute()需要在主線程調(diào)用,若在子線程中調(diào)用,那么在onPreExecute就會(huì)在子線程中運(yùn)行,那么操作UI相關(guān)的操作就會(huì)出問(wèn)題。
  11. AsyncTask異步任務(wù)不可以被執(zhí)行多次,每一個(gè)異步任務(wù)都會(huì)有一個(gè)狀態(tài)標(biāo)記,分別為PENDDING,RUNING,FINISH,只要狀態(tài)不是為PENDING都會(huì)拋出異常。
  12. AsyncTask#cancel(boolean)設(shè)置取消異步任務(wù),設(shè)置之后會(huì)調(diào)用onCancelled()通知用戶。
  13. AsyncTask#onCancelled()在finish()中判斷當(dāng)前狀態(tài)是否為取消狀態(tài),取消狀態(tài)的話則調(diào)用onCancelled(Result)方法。
  14. AsyncTask默認(rèn)是串行執(zhí)行的,需要并行執(zhí)行異步任務(wù)的話則需要在executeOnExecutor方法傳遞一個(gè)Executor就可以實(shí)現(xiàn)并行執(zhí)行。

1. AsyncTask構(gòu)造方法

實(shí)例化對(duì)象中,實(shí)例化了mWorker,mFuture對(duì)象,具體實(shí)現(xiàn)待會(huì)具體分析。

public AsyncTask() {
    mWorker = new WorkerRunnable<Params, Result>() {
    public Result call() throws Exception{
            ...
        }
    };
    mFuture = new FutureTask<Result>(mWorker) {
    @Override
    protected void done() {
            ...
        }
    };
}

2.WorkerRunnable&FutureTask

從類的定義可以知道m(xù)Worker是Callable的子類對(duì)象,mFuture是Runnabel的子類對(duì)象。

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}

public interface RunnableFuture<V> extends Runnable, Future<V> {}
public class FutureTask<V> implements RunnableFuture<V> {}

3.AsyncTask#execute(Params... params)

有了AsyncTask實(shí)例之后,怎樣去開(kāi)始執(zhí)行一個(gè)異步任務(wù)?可以通過(guò)execute方法開(kāi)啟一個(gè)異步任務(wù)。有一個(gè)疑問(wèn)?params是什么?我們看源碼得出去找params用來(lái)干嘛。execute會(huì)通過(guò)executeOnExecutor(Executor exec,Params... params) 去執(zhí)行任務(wù)。

@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}

4.AsyncTask#executeOnExecutor(Executor exec,Params... params)

從源碼中可知道execute傳遞的params原來(lái)是會(huì)被賦值給mWorker.params,具體什么作用,我們先不分析,待會(huì)用到再說(shuō)?,F(xiàn)在我們看到一個(gè)熟悉的方法,那就是onPreExecute(),這證實(shí)了AsyncTask的第(1)條結(jié)論,那就是onPreExecute()是在主線程中運(yùn)行(前提:AsyncTask是在主線程創(chuàng)建的),然后是在異步任務(wù)執(zhí)行之前調(diào)用,通常用于準(zhǔn)備工作。

@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) {
    ...
    onPreExecute();//異步執(zhí)行之前調(diào)用。
    mWorker.mParams = params;
    exec.execute(mFuture);//將任務(wù)放到線程池的,開(kāi)始異步任務(wù)。
    return this;
}

疑問(wèn)1:exec是什么?

它是一個(gè)線程池,從傳入的參數(shù)sDefaultExecutor可以看出,它是一個(gè)默認(rèn)的線程池,內(nèi)部維護(hù)一個(gè)ArrayDeQue隊(duì)列。AsyncTask里默認(rèn)維護(hù)了一個(gè)靜態(tài)的線程池,不管有多少個(gè)AsyncTask調(diào)用execute方法都會(huì)去共享這個(gè)靜態(tài)的線程池,該線程池只允許一次運(yùn)行一個(gè)任務(wù),多余的任務(wù)需要等待,這印證了第(8)點(diǎn)結(jié)論。SerialExecutor內(nèi)部只是維護(hù)了一個(gè)隊(duì)列,真正執(zhí)行任務(wù)還是THREAD_POOL_EXECUTOR 去執(zhí)行。代碼如下:

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//默認(rèn)的線程池就是它
private static class SerialExecutor implements Executor {
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();//內(nèi)部維護(hù)一個(gè)隊(duì)列

    public synchronized void execute(final Runnable r) {
        ...
        //真正執(zhí)行任務(wù)還是THREAD_POOL_EXECUTOR 去執(zhí)行,代碼暫時(shí)不貼。
    }
     ...
}

疑問(wèn)2:怎么體現(xiàn)異步任務(wù)在子線程執(zhí)行?

答案就在SerialExecutor#execute怎么去執(zhí)行Runnbale的?mTasks.offer將一個(gè)Runnabel添加到mTask中,這樣做的目的就是按順序地去執(zhí)行任務(wù),具體的實(shí)現(xiàn)就在scheduleNext()中?,F(xiàn)在所處就是在子線程中了

 private static class SerialExecutor implements Executor {
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();//不支持并發(fā)訪問(wèn),是一個(gè)Collection數(shù)據(jù)結(jié)構(gòu),不安全
        Runnable mActive;

     public synchronized void execute(final Runnable r) {
         mTasks.offer(new Runnable() {//插入一個(gè)Runnable對(duì)象
             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);
         }
     }
}

5.FuturnTask#run()

execute方法的最終會(huì)調(diào)用Runnable中run方法被執(zhí)行,也就是說(shuō)mFuture#run會(huì)被執(zhí)行,接下來(lái)看看run怎么實(shí)現(xiàn)的

public void run() {
    Callable<V> c = callable;//就是 mWorker 對(duì)象
    ...
    V result;
    result = c.call();//開(kāi)始計(jì)算
    ...
    if (ran)
        set(result);
}
           

疑問(wèn)1:callable是什么?

callable實(shí)際上就是在AsyncTask構(gòu)造中傳遞給mFuture的構(gòu)造參數(shù)(mWorker對(duì)象)

public FutureTask(Callable<V> callable) {
   if (callable   null)
       throw new NullPointerException();
   this.callable = callable;
   this.state = NEW;       // ensure visibility of callable
}

疑問(wèn)2:result又是什么?

分析:result = c.call()將子線程中運(yùn)行的結(jié)果賦值給result。result的類型就是Callable<V>的泛型類型。在mFuture初始化的時(shí)候已經(jīng)被指定Result類型,也就是在AscnycTask異步任務(wù)執(zhí)行結(jié)果返回值類型。接下來(lái)看看call怎么去計(jì)算異步結(jié)果的。

6.計(jì)算異步結(jié)果WorkerRunnable#call()

標(biāo)記postResult方法調(diào)用的標(biāo)記,這句話的作用現(xiàn)暫時(shí)放著,待會(huì)再解釋。這時(shí)候我們又看到熟悉的身影了(doInBackground),這段代碼實(shí)在子線程中執(zhí)行的,也就印證了第(2)條結(jié)論。將返回結(jié)果傳遞給postResult,接下來(lái)看看postResult的實(shí)現(xiàn)

public Result call() throws Exception {
    mTaskInvoked.set(true);//標(biāo)記postResult為被調(diào)用
    Result result = doInBackground(mParams);
    return postResult(result);
};

7.AsyncTask#postResult

大家看到這里相信應(yīng)該都有點(diǎn)眉目了,剛才call方法是在子線程中運(yùn)行的,現(xiàn)在出現(xiàn)的Message和Handler的身影,那么100%就將異步結(jié)果放到主線程中去。我們看看怎么實(shí)現(xiàn):

private Result postResult(Result result) {
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
    new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

8.InternalHandler消息機(jī)制實(shí)現(xiàn)消息的放松

既然需要更新UI,那么就需要將消息發(fā)送到主線程中去,那么就得拿到主線程中的Looper輪訓(xùn)器,在InternalHandler中的構(gòu)造可以看到,獲取到的Looper是主線程中的。
在這里可以看到兩個(gè)case:MESSAGE_POST_RESULT是在postResult中調(diào)用,MESSAGE_POST_PROGRESS是在publishProgress中調(diào)用的
然后在onProgressUpdate中去調(diào)用,該方法是在需要子類去實(shí)現(xiàn)處理的,在該方法中將數(shù)據(jù)回調(diào)在主線程去。 印證了第(7)點(diǎn)結(jié)論

public InternalHandler() {
    super(Looper.getMainLooper());
}

@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);//印證第(5)結(jié)論
        break;
        }
    }
}

@WorkerThread
protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

9.AsyncTask#finish(Result result)

在該方法中我又看到一個(gè)熟悉的身影那就是onPostExecute,由于finish是在handleMessage中調(diào)用的,所以它也是在主線程中調(diào)用,并且有Result結(jié)果,可以更新UI。 這里就印證了第(3)條結(jié)論 。

private void finish(Result result) {
    if (isCancelled()) {//判斷是否取消
        onCancelled(result);
    } else {//沒(méi)有取消
        onPostExecute(result);//將結(jié)果傳遞給該方法,主線程更新UI
    }
    mStatus = Status.FINISHED;//更新標(biāo)記為完成
}

10.FuturnTask#set(result)

在call方法將結(jié)果計(jì)算之后,就需要將該結(jié)果保存起來(lái),set方法就是做這件事的,在set中將result結(jié)果賦值給outcome,并且調(diào)用FutureTask#done(),看到這里我們會(huì)有點(diǎn)印象,那就是在 AsyncTask構(gòu)造中實(shí)例化mFuture時(shí)重寫了done()方法,這個(gè)方法就是在這里回調(diào)的 。下面我們看看done做了什么事?

protected void set(V v) {
    if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
        //將計(jì)算的結(jié)果保存到 outcome 中。
        outcome = v;
        U.putOrderedInt(this, STATE, NORMAL); // final state
        finishCompletion();
    }
}

11.FutureTask#done()

該方法由子類去實(shí)現(xiàn),當(dāng)異步任務(wù)執(zhí)行完畢之后會(huì)調(diào)用。該方法被調(diào)用表示Callable#call()方法的計(jì)算結(jié)果已經(jīng)被保存在outcome中了,在需要的地方取出即可。done()除了在finishCompletion()中調(diào)用外,還有innerCancel(boolean)中調(diào)用,這個(gè)接下來(lái)再分析。

mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
    ...
    postResultIfNotInvoked(get());
    ...
};

get()是什么?可以源碼直到,它實(shí)質(zhì)上返回就是我們剛才說(shuō)的call方法計(jì)算返回的值(outcome)。該值傳遞給postResultIfNotInvoked(Result result)又做了什么事呢?

12.postResultIfNotInvoked(Result result)

當(dāng)看到這個(gè)wasTaskInvoked這個(gè)值的時(shí)候,我們應(yīng)該有一丟丟印象,那就是在call方法執(zhí)行的該標(biāo)記被置為true了。這時(shí)候被取出來(lái)也是為true,那么接下來(lái)的代碼就沒(méi)執(zhí)行了。現(xiàn)在有一個(gè)疑問(wèn),if條件在什么情況會(huì)成立呢?請(qǐng)看異步任務(wù)取消的代碼就直到了。

private void postResultIfNotInvoked(Result result) {
    final boolean wasTaskInvoked = mTaskInvoked.get();
    if (!wasTaskInvoked) {//wasTaskInvoked這個(gè)標(biāo)記唯一被賦值的地方就是call方法,標(biāo)記為true表示postResult被調(diào)用,那么就不要再調(diào)用postResultIfNotInvoked方法了,除非cancel了該任務(wù),導(dǎo)致在call方法沒(méi)有對(duì)該標(biāo)記賦值,所以該方法就會(huì)被調(diào)用。
        postResult(result);
    }
}

13.AsyncTask#postResult()

private Result postResult(Result result) {
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new       AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

14.取消異步任務(wù)AsyncTask#cancel(boolean)

將取消標(biāo)記為true,并且調(diào)用mFuture#cancel取消任務(wù)。

public final boolean cancel(boolean mayInterruptIfRunning) {
    mCancelled.set(true);
    return mFuture.cancel(mayInterruptIfRunning);
}

15.FutureTask#cance(boolean)

在該方法中也執(zhí)行了done()方法,該方法在AsyncTask構(gòu)造中已經(jīng)可以看到,直接回到先前的代碼查閱,它會(huì)去調(diào)用postResultIfNotInvoked(Result),這就解釋了為什么這個(gè)方法的命名,當(dāng)異步任務(wù)沒(méi)有執(zhí)行完畢,它是不會(huì)去執(zhí)行設(shè)置mTaskInvoked.set(true)的,因此該方法就可以順利成章的執(zhí)行了。代碼最終會(huì)去執(zhí)行postResult。

boolean innerCancel(boolean mayInterruptIfRunning) {
    ...
    done();
    return true;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容