AsyncTask 源碼詳解

感謝鴻神大大提供的資料,本想直接轉載的,後來發現有些東西弄的不是太清楚,所以就直接自己總結吧,有興趣的可以自己看下鴻神的 blog,我這裏就不講 Executor 這塊的知識了,我又沒弄懂,講出來也是直接 copy 過來的,沒意思。

進入正題,可能現在大多數人還是在使用 Thread + Handler 來處理線程,或者直接線程池處理,其實我也是這樣,畢竟理解起來簡單,而且代碼也容易寫(相對於 AsyncTask),如果使用 AsyncTask,我們怎麼做呢?

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        addAsyncTaskText()
    }

    fun addAsyncTaskText() {
        MyAsyncTaskText("aaaaaaaaaaa").execute("")
    }

    companion object {
        open class MyAsyncTaskText(var content: String) : AsyncTask<String, Int, String>() {

            /**
             * 準備工作  運行在主線程 
             */
            override fun onPreExecute() {
                super.onPreExecute()
            }

            /**
             * 運行在線程中 
             */
            override fun doInBackground(vararg params: String?): String {
                return content
            }

            /**
             * 運行在主線程 
             */
            override fun onProgressUpdate(vararg values: Int?) {
                super.onProgressUpdate(*values)
            }

            /**
             * 運行在主線程 返回值
             */
            override fun onPostExecute(result: String?) {
                super.onPostExecute(result)
            }
        }
    }

當時第一次用的時候,對於 onPreExecute、doInBackground、onProgressUpdate 和 onPostExecute 這四個方法,哪個運行在主線程可以更新 UI,哪個運行在子線程,不能做 UI 操作(請不要較真,謝謝),我只能死記硬背,時隔多年,正好閒着沒事幹,就準備研究下它的源碼。

源碼解析

既然有 AsyncTask 的執行方法,那我們先從它的執行方法來看,

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

繼續往下找,來看 executeOnExecutor 方法:

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

代碼不多,但是涉及到了好多內容,我們一個一個的來解析,先來看下這個方法用啥用,根據官方註解來看下:

 通過這個方法我們可以自定義 AsyncTask 的執行方式,串行 or 並行,甚至可以採用自己的 Executor 爲了實現並行,我們可以在外部這麼用 AsyncTask:asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Params... params);  必須在UI線程調用此方法。

原來如此,這個方法可以用來串行或者並行,使用 AsyncTask 比較多的讀者應該知道,在 Android 3.0 以前,AsyncTask 是並行的,而在 Android 3.0 以後包含 Android 3.0,AsyncTask 是串行的,那麼難道真的沒有辦法在 Android 3.0 以後讓 AsyncTask 並行開發嗎,並不是,後面會講解,如何實現讓 AsyncTask 並行執行。

我們繼續看 executeOnExecutor 源碼,我們來看下第 15 行,先來說下這個狀態,它是 AsyncTask 中的一個枚舉類:

    public enum Status {
        /**
         * 任務等待執行
         */
        PENDING,
        /**
         * 任務已經執行
         */
        RUNNING,
        /**
         * 任務已經執行結束
         */
        FINISHED,
    }

我們看到第 17 行執行的是 onPreExecute 方法,而在 Android 3.0 以後到 Android 4.0.1 以前,executeOnExecutor 是執行在主線程的,而在 Android 4.0.1 以後,AsyncTask 是可以在子線程實例化的。

1. WorkerRunnable

繼續往下看第 19 行,我們發現有一個 mWorker 出現了,那麼它是什麼呢,我們來看下 AsyncTask 的構造函數:

   public AsyncTask(@Nullable Looper 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;
            }
        };
    }

我們發現 AsyncTask 的構造函數實例化了一個 WorkerRunnable 類,並重寫了 WorkerRunnable 的 call 方法,那麼 WorkerRunnable 到底是個什麼呢,我們繼續往下看:

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

它只是用來接收我們傳遞給 AsyncTask 數據的一個類。

在構造方法中,在 call 方法中,調用了我們最熟悉的 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;
    }

哈哈,熟悉的代碼,忽然找到了親切感,原來是這樣,線程想更新 UI,始終擺脫不了 Handler 啊,那麼我們就來找到這個 Handler:

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

我們來看下 switch 這段代碼,第一個 case 的值正好對應 postResult 方法中發送的值啊,那就來看下 finish 方法唄,

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

好嘛,這裏進行了一次判斷,是否被取消,取消調用 onCancelled,否則調用 onPostExecute,還記得 AsyncTask 構造中 try ... catch 中拋出的異常嗎?

  mCancelled.set(true);

通過 finish 方法,我們知道它是運行在主線程的,並且裏邊調用了 onPostExecute,也就說明了 onPostExecute 運行在主線程了。最後把狀態設置成 FINISHED 狀態。

2. FutureTask

看完了 WorkerRunnable,我們繼續來看下一個重點,FutureTask,繼續來看 AsyncTask 的構造:

    public AsyncTask(@Nullable Looper callbackLooper) {
        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);
                }
            }
        };
    }

只執行了一個方法 postResultIfNotInvoked,那麼它到底有什麼用呢?其實啊,postResultIfNotInvoked 的中的那個 get 方法獲取的就是 mWorker 中的那個 Result 值,來看下 postResultIfNotInvoked 方法:

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

如果 wasTaskInvoked 爲 false,則執行 postResult,但是在 AsyncTask 的構造中,wasTaskInvoked 就已經被設置爲了 true,

public AsyncTask(@Nullable Looper callbackLooper) {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                ...
                return result;
            }
        };
    }

所以呢,這裏的 postResult 一般不會執行,具體什麼時候執行呢,我在研究下。

還有一個方法沒有說到,這裏來說下,在 doInBackground 中執行了我們需要講解的方法,onProgressUpdate 方法:

    @Override
    protected ReusableBitmap doInBackground(Void... params) {
        // enqueue the 'onDecodeBegin' signal on the main thread
        publishProgress();

        return decode();
    }

我們來看下 publishProgress 方法:

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

還記得我們那個 Handler 的 switch 嗎?我們只說了第一個 case ,我們來看第二個 case:

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

在第二個 case 中,執行了我們可以重寫的 onProgressUpdate 方法,這也是爲什麼他可以做進度條的原因了。

並行執行

在上邊我給出的例子只是串行執行的,那麼在 Android 3.0 及以後怎麼並行執行呢,其實呢,也很簡單,我們只需要調用 AsyncTask 的 executeOnExecutor 方法而不是 execute 就可以了啊。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        addAsyncTaskText()
    }

    fun addAsyncTaskText() {
        MyAsyncTaskText("aaaaaaaaaaa").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"")
    }

    companion object {
        open class MyAsyncTaskText(var content: String) : AsyncTask<String, Int, String>() {

            /**
             * 準備工作  運行在主線程
             */
            override fun onPreExecute() {
                super.onPreExecute()
            }

            /**
             * 運行在線程中
             */
            override fun doInBackground(vararg params: String?): String {
                return content
            }

            /**
             * 運行在主線程
             */
            override fun onProgressUpdate(vararg values: Int?) {
                super.onProgressUpdate(*values)
            }

            /**
             * 運行在主線程 返回值
             */
            override fun onPostExecute(result: String?) {
                super.onPostExecute(result)
            }
        }
    }

好了,關於 AsyncTask 的源碼已經分析完了,有錯的地方請指出,謝謝!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章