AsyncTask源碼解析

導(dǎo)語(yǔ)

AsyncTask對(duì)Android開(kāi)發(fā)者來(lái)說(shuō)并不陌生,當(dāng)有耗時(shí)任務(wù)并涉及UI交互,AsyncTask可是處理異步任務(wù)的利器。AsyncTask使用也很方便,開(kāi)發(fā)的時(shí)候多留意不要內(nèi)存泄漏,一般處理方法就是把AsyncTask寫(xiě)成靜態(tài)內(nèi)部類(lèi)的形式。

使用方法
new AsyncTask<Integer, Integer, Boolean>() {

            private int NUM = 0;

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                textView.setText("onPreExceute");
            }

            @Override
            protected Boolean doInBackground(Integer... integers) {
                for (int i = 0; i < 20; i++) {
                    try {
                        NUM ++;
                        publishProgress(NUM);
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                return NUM == 20;
            }

            @Override
            protected void onPostExecute(Boolean aBoolean) {
                super.onPostExecute(aBoolean);
                textView.setText("onPostExcute: " + aBoolean);
            }

            @Override
            protected void onProgressUpdate(Integer... values) {
                super.onProgressUpdate(values);
                textView.setText("onProgressUpdate: " + values[0]);
            }

            @Override
            protected void onCancelled(Boolean aBoolean) {
                super.onCancelled(aBoolean);
                textView.setText("onCancelled: " + aBoolean);
            }

            @Override
            protected void onCancelled() {
                super.onCancelled();
                textView.setText("onCancelled");
            }

        }.execute(1);
關(guān)鍵方法

onPreExecute、doInBackground、publishProgress、onPostExecute、onProgressUpdate、onCancelled是AsyncTask的幾個(gè)關(guān)鍵方法,開(kāi)發(fā)者可處理自己的邏輯。除了doInBackground在異步線程執(zhí)行外,publishProgress可在任意線程處理,其他方法都是在UI線程處理。publishProgress和onProgressUpdate配合使用。

參數(shù)

Integer, Integer, Boolean,在AsyncTask三個(gè)參數(shù)的呈現(xiàn)形式是:Params,Progress,Result,從字面意思我們就知道,Params即入?yún)ⅲ琍rogress即進(jìn)度,Result即返回結(jié)果,可根據(jù)實(shí)際業(yè)務(wù)邏輯靈活配置。

源碼分析
從execute()開(kāi)始吧
  @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
 @MainThread
    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;
    }

Status有三個(gè)值:PENDING、RUNNING、FINISHED,分別表示初始、運(yùn)行、結(jié)束三個(gè)狀態(tài)。
從executeOnExecutor方法里可以看出,一開(kāi)始執(zhí)行Status狀態(tài)就置成了RUNNING運(yùn)行狀態(tài),這里出現(xiàn)了關(guān)鍵方法之一 onPreExecute,也就是執(zhí)行異步任務(wù)doInBackground前的一個(gè)狀態(tài),一般用來(lái)處理界面元素初始化相關(guān),運(yùn)行在UI線程。下面兩行代碼則開(kāi)啟了doInBackground的工作:

mWorker.mParams = params;
exec.execute(mFuture);

mWorker是什么呢?mFuture又是什么呢?我們知道exec是一個(gè)Executor對(duì)象,說(shuō)明它是一個(gè)線程池,那么可以知道m(xù)Future應(yīng)該是Runnable或Callable對(duì)象。mWorker對(duì)象則承載了入?yún)ⅲ蚼Future肯定是依賴(lài)關(guān)系。繼續(xù)往下深入,一探mFuture和mWorker的究竟。
在AsyncTask構(gòu)造方法里面,發(fā)現(xiàn)了這兩個(gè)對(duì)象的初始化相關(guān):

public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        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);
                }
            }
        };
    }

原來(lái)mWorker是一個(gè)Runnable,mFuture是一個(gè)FutureTask,mWorker用mFuture來(lái)承載。
FutureTask在平時(shí)開(kāi)發(fā)過(guò)程中用的較少,可能很多開(kāi)發(fā)者對(duì)它還有些陌生。這里做個(gè)簡(jiǎn)單介紹:FutureTask是一個(gè)用來(lái)執(zhí)行異步任務(wù)的類(lèi),同時(shí)當(dāng)程序執(zhí)行完成之后還會(huì)返回運(yùn)算的結(jié)果。官方釋義:這是一個(gè)可以取消的異步計(jì)算,該類(lèi)提供了Future的基本實(shí)現(xiàn),具有啟動(dòng)和取消運(yùn)算,查詢(xún)運(yùn)算是否結(jié)束,并且檢查返回計(jì)算的結(jié)果,該結(jié)果只能在運(yùn)行完成之后才能獲取到,如果程序沒(méi)有運(yùn)行結(jié)束,則get()將會(huì)阻塞。程序運(yùn)行結(jié)束之后,無(wú)法重新啟動(dòng)或者是取消程序(除非調(diào)用runAndReset方法)。FutureTask可以承載Callable和Runnable,兩者的區(qū)別是:Callable可以攜帶返回參數(shù),而Runnable不支持。
我們來(lái)看看mWorker的實(shí)現(xiàn):

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

WorkerRunnable是一個(gè)抽象類(lèi),繼承自Callable,并攜帶了Result參數(shù),由于AsyncTask是一個(gè)帶結(jié)果返回的對(duì)象,所以用Callable實(shí)現(xiàn)。這里可以知道AsyncTask構(gòu)造方法里的mWorker即是WorkerRunnable的具體實(shí)現(xiàn),抽象類(lèi)里只是承載了入?yún)ⅰ?/p>

到這里,就清楚AsyncTask整體的運(yùn)行模式了:Executor —> FutureTask —> Callable 。內(nèi)部維護(hù)一個(gè)線程池,線程池處理異步任務(wù),異步任務(wù)承載Callable進(jìn)行任務(wù)的執(zhí)行。

繼續(xù)深入,mWoker就類(lèi)似一個(gè)帶任務(wù)的小兵,具體的執(zhí)行工作都在它身上完成。一探mWoker究竟吧。具體實(shí)現(xiàn)代碼再拎出來(lái):

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;
            }
        };

在回調(diào)的call方法里,我們發(fā)現(xiàn)關(guān)鍵方法之二doInBackground,說(shuō)明異步任務(wù)在這里執(zhí)行,返回了Result對(duì)象。Process.setThreadPriority設(shè)置了線程優(yōu)先級(jí),這里任務(wù)在后臺(tái)執(zhí)行,所以?xún)?yōu)先級(jí)設(shè)置成THREAD_PRIORITY_BACKGROUND。關(guān)于Binder.flushPendingCommands(),官方釋義:將當(dāng)前線程中掛起的任何綁定命令刷新到內(nèi)核驅(qū)動(dòng)程序中。在執(zhí)行可能很長(zhǎng)時(shí)間阻塞的操作之前調(diào)用此功能是有用的,以確保任何掛起的對(duì)象引用已被釋放,以防止進(jìn)程對(duì)對(duì)象持有比它所需時(shí)間更長(zhǎng)的時(shí)間。這里不做深究。異步任務(wù)執(zhí)行完畢又是如何告知UI線程的呢?這里的邏輯我們要看FutureTask的具體實(shí)現(xiàn)和處理了:

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);
                }
            }
        };

可以看出當(dāng)任務(wù)執(zhí)行完畢,即在done方法回調(diào)里由postResultIfNotInvoked處理:

 private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

可以看出返回的結(jié)果對(duì)象Result最終通過(guò)postResult方法執(zhí)行,去看看:

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

發(fā)現(xiàn)這就是我們常用的handler啊,這里發(fā)送了一條msg.what=MESSAGE_POST_RESULT,msg.object=AsyncTaskResult的消息給getHandler()。繼續(xù)看看getHandler()怎么處理的:

private Handler getHandler() {
        return mHandler;
    }

這。。。不是我想要的結(jié)果啊。好吧,繼續(xù)追蹤mHandler。才發(fā)現(xiàn)早在AsyncTask構(gòu)造方法里就對(duì)mHandler進(jìn)行了初始化。

mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

好吧,繼續(xù)看getMainHandler()具體實(shí)現(xiàn):

private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

繼續(xù)吧,看InternalHandler具體實(shí)現(xiàn):

private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }

        @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;
            }
        }
    }

終于找到了handler的具體實(shí)現(xiàn),這里發(fā)現(xiàn)了關(guān)鍵方法之三onProgressUpdate,可以看到他處理兩類(lèi)消息:MESSAGE_POST_RESULT和MESSAGE_POST_PROGRESS。很顯然這里的邏輯都是在UI線程發(fā)生。MESSAGE_POST_RESULT處理異步任務(wù)執(zhí)行完返回的Result,可以知道MESSAGE_POST_PROGRESS應(yīng)該就是處理publishProgress發(fā)送的消息了。
看看publishProgress的實(shí)現(xiàn):

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

這里發(fā)現(xiàn)了關(guān)鍵方法之三publishProgress,可以看出,MESSAGE_POST_PROGRESS通過(guò)publishProgress發(fā)出,和MESSAGE_POST_RESULT發(fā)送對(duì)象的參數(shù)不一樣,MESSAGE_POST_PROGRESS攜帶的是Progress,MESSAGE_POST_RESULT攜帶的是Result。這邏輯也是通的,看來(lái)AsyncTaskResult也就是一個(gè)數(shù)據(jù)對(duì)象啦。看看具體實(shí)現(xiàn):

 @SuppressWarnings({"RawUseOfParameterizedType"})
    private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

好了,到這里我們已經(jīng)理清異步任務(wù)執(zhí)行的結(jié)果或是執(zhí)行過(guò)程中的進(jìn)度是如何通知UI線程處理了。那么異步處理完成后返回的Result又是如何處理的呢?繼續(xù)往下看:

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;
            }

對(duì)于Result的處理方式:result.mTask.finish(result.mData[0]);result.mTask即AsyncTask本身,我們具體看看它的finish方法具體實(shí)現(xiàn):

private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

這里發(fā)現(xiàn)了關(guān)鍵方法之四onPostExecute和關(guān)鍵方法之五onCancelled。如果任務(wù)沒(méi)有被取消,則執(zhí)行onPostExecute,同時(shí)Status置于FINISHED,任務(wù)結(jié)束。

到這里,AsyncTask幾個(gè)關(guān)鍵方法的執(zhí)行時(shí)機(jī)和來(lái)龍去脈已經(jīng)清楚,通過(guò)handler進(jìn)行關(guān)聯(lián)處理。

我們知道AsyncTask可以同時(shí)處理多個(gè)Runnable任務(wù),那么內(nèi)部又是如何保證執(zhí)行順序呢?初步判斷是和線程池相關(guān),于是看看AsyncTask維護(hù)的線程池具體實(shí)現(xiàn):

線程池配置:

 static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

線程池的具體執(zhí)行類(lèi):

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);
            }
        }
    }

可以發(fā)現(xiàn)SerialExecutor內(nèi)部維護(hù)了一個(gè)ArrayDeque隊(duì)列,里面可以裝載很多Runnable。沒(méi)當(dāng)執(zhí)行一個(gè)Runnable的時(shí)候,將該Runnable添加到隊(duì)列尾部,每次執(zhí)行Runnable的時(shí)候從隊(duì)尾獲取Runnable對(duì)象。第一個(gè)Runnable任務(wù)執(zhí)行的時(shí)候,mActive==null,所以會(huì)去執(zhí)行scheduleNext()方法并把該runnable賦值給mActive,當(dāng)?shù)诙€(gè)Runnable執(zhí)行的時(shí)候,mActive!=null,就不會(huì)去執(zhí)行scheduleNext了嗎?當(dāng)然不是,我們可以發(fā)現(xiàn)run方法回調(diào)里用了try finally方法,意思是任何一個(gè)Runnable,執(zhí)行完畢后都會(huì)去執(zhí)行scheduleNext方法。這樣相當(dāng)于保證每個(gè)Runnable任務(wù)都是等上個(gè)Runnable執(zhí)行完畢后才會(huì)去執(zhí)行。

好了,關(guān)于AsyncTask的源碼解析主要邏輯都在這了。其中涉及的一些細(xì)節(jié),可以自行去查找資料了解。比如用AutomicBoolean來(lái)判斷任務(wù)是否取消(mCancelled)或已經(jīng)開(kāi)始執(zhí)行(mTaskInvoked)。

為更好地理解AsyncTask,建議大家參照AsyncTask源碼,造個(gè)輪子,畢竟代碼量不大。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評(píng)論 6 535
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,744評(píng)論 3 421
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,879評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,181評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,935評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,325評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評(píng)論 3 443
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,534評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,084評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,892評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,067評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,322評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,735評(píng)論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,990評(píng)論 1 289
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,800評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,084評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容