Android進階知識樹——AsyncTask的使用和源碼分析

一、概述

  • AsyncTask的做用:首先看看API中對AsyncTask的官方解釋
<p>AsyncTask enables proper and easy use of the UI thread. This class allows you
 * to perform background operations and publish results on the UI thread without
 * having to manipulate threads and/or handlers.</p>複製代碼
  1. 上述這句話翻譯的意思是:AsyncTask可以正確使用UI線程。容許您在UI線程上執行後臺操做和發佈結果,而沒必要操縱線程和/或處理程序
  • AsyncTask的主要方法
  1. AsyncTask<Params, Progress, Result>: 繼承AsyncTask須要傳入三個參數類型;Params:後臺任務的輸入參數類型,Progress:中間進度的數據類型,Result : 執行結果的數據類型
  2. protected void onPreExecute() :執行後臺任務的準備工做
  3. abstract Result doInBackground(Params... params):根據參數和邏輯在後臺執行操做任務並返回執行的結果,抽象方法必須實現
  4. void onProgressUpdate(Progress... values) :在操做執行時刷新操做進度,須要配合void publishProgress(Progress... values)方法使用
  5. void onPostExecute(Result result):返回執行的結果

二、使用

  • 以一個簡單例子使用AsyncTask的執行,並輸出相應的線程信息,使用方法建立類繼承AsyncTask,並重寫相應的方法,代碼以下:
inner class TestAsyncTask : AsyncTask<Int, Int, String>() {

        override fun doInBackground(vararg params: Int?): String {
            Log.e("method:", "doInBackground()")
            Log.e("Thread:", Thread.currentThread().name)
            val stringBuilder = StringBuilder()
            for (i in params[0]!!..params[0]!! + 10) {   // 輸出信息
                stringBuilder.append(i)
                publishProgress(i)   // 更新當前進度
                Thread.sleep(500)
            }
            return stringBuilder.toString()
        }

        override fun onPreExecute() {
            super.onPreExecute()
            Log.e("method:", "onPreExecute()")
            Log.e("Thread:", Thread.currentThread().name)
        }

        override fun onProgressUpdate(vararg i: Int?) {
            super.onProgressUpdate(*i)
            Log.e("method:", "onProgressUpdate()")
            Log.e("Thread:", Thread.currentThread().name)
            Log.e("Progress:", i.toString())
        }
        
        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)
            Log.e("method:", "onPostExecute()")
            Log.e("Thread:", Thread.currentThread().name)
        }
    }複製代碼
  • 在Activity中的調用
TestAsyncTask().execute(0)複製代碼
  • 執行結果:

  1. 從上面的執行結果中看出只有DoInBackground()方法,執行在非UI線程,其他的輸出都切換在UI線程,這也就說明l開頭的解釋:無需開發者對線程管理,AsyncTask會自動切換線程執行任務和輸出結果

三、源碼分析

相信對於AsyncTask 的使用沒什麼難度,系統封裝好了處理數據和線程的功能,只需按照步驟把要執行的邏輯放進去就行了,如今來看看AsyncTask 是如何處理了複雜邏輯而卻給咱們提供簡單的使用方法,咱們知道AsyncTask 的執行是從調用AsyncTask().execute()開始的,一塊兒來看看他的源碼吧:android

@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) {  //判斷此時的AsyncTask對象的狀態
            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;  //標記AsyncTask對象爲運行狀態
        onPreExecute();            
        mWorker.mParams = params;  //設置任務參數
        exec.execute(mFuture);
        return this;
    }複製代碼

從源碼中能夠看出execute()的方法執行過程:數組

  1. 從方法註解中看出execute()必須在主線程中調用
  2. 在execute()方法中調用executeOnExecutor()傳入Executor實例和參數params
  3. executeOnExecutor()中,首先判斷運行狀態,AsyncTask提供三種運行狀態:PENDING(未執行)、RUNNING(執行中)FINISHED(完成)三種狀態,只有在PENDING狀態下才可執行,且每一個對象只能執行一次
  4. 調用onPreExecute()方法初始化數據,此時方法執行在Main線程中
  5. 設置參數,並執行任務

上述所述的執行過程外,方法中還出現了三個變量:sDefaultExecutor mWorkermFuture,從變量的名稱和執行的操做咱們姑且能夠猜想一下,sDefaultExecutor 應該爲任務的直接執行者(即線程、線程池)或間接調用線程執行,mWork對執行參數的封裝,mFuture是在exec.execute(mFuture)中執行的,因此應該Runnable類的實例,三個對象實現了任務的保存、獲取、執行者、如何執行;那若是咱們搞懂了這幾個類的工做過程也就搞懂了AsyncTask的實現。bash

3.1 sDefaultExecutor app

  • 查看源碼
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

 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);
            }
        }
    }
複製代碼
  1. sDefaultExecutor是在開始就初始化好的SerialExecutor的實例,sDefaultExecutor最終調用的是SerialExecutor中的execute()方法執行任務
  2. SerialExecutor類中建立一個Runnable隊列ArrayDeque<Runnable> Task,用於保存和獲取sDefaultExecutor傳遞的任務
  3. execute()方法中首先將Runnable添加到對列Task中,而後調用mTask.poll()取出頭部的Runnable對象,每次執行完後都會調用schedule獲取下一個任務,從而實現任務串行處理
  4. 將拿到的Runnable對象交給THREAD_POOL_EXECUTOR執行,很顯然 THREAD_POOL_EXECUTOR爲線程池,建立過程以下:
private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);   // 任務隊列

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

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;
    }複製代碼

上述爲手動建立線程池的基本過程,還記得前面的Log中執行onBackground()的線程 AsyncTask #1嗎;就是在這個地方建立的,也間接說明了真正執行任務的是線程池ide

忽略參數細節處理的話,到此Async的執行流程基本出來了,首先調用execute()方法 --> 判斷狀態是否爲PENDING -->調用prepare準備數據 -->函數

系列的參數操做 -->在SerialExecutor中的隊列中保存任務 -> 取出頭部任務 --> 線程池執行取出的任務;

3.2 mWorkeroop

從上面的賦值能夠看出,mWork保存了AsyncTask傳入的參數params,下面看看它是如何執行的:源碼分析

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

 mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    result = doInBackground(mParams);//執行任務
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };複製代碼
  1. mWork是WorkRunnable的實例,包含保存參數的數組Params,這也驗證了咱們以前的猜測;
  2. 在AsynTask 的構造函數中建立了mWork,重寫了Callable的call(),在方法中調用doInBackground()執行任務
  3. 使用mTaskInvoked保存true,此處只是保持一個標誌位,具體做用在下面會看到
  4. 在獲得返回結果Result後,經過postResult()發送數據,postResult()中使用Handler切換線程發送結果,此處的Handler必定在主線程中,詳細的Handler後面會介紹
private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }複製代碼

3.2 mFuturepost

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);
                }
            }
        };複製代碼

還記的前面的判斷嗎?mFuture 爲Runnable的對象,在AsyncTask中一樣也實例化了mFuture的對象,實現done()方法,調用 postResultIfNotInvoked()傳遞結果:ui

private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }複製代碼
  1. 調用mTaInvoked.get()判斷是否已經發送過結果,想起前面mWorker的設置 mTaskInvoked.set(true)了吧,若是已經設置爲true表示已經執行過mWork的call(),即已經發送過數據,若是獲取爲false再次調用postResult發送

3.4 線程池執行mFuture

  • 線程池執行後會調用mFuture的run()方法,源碼以下:
public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();//調用call()
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }複製代碼
  1. 首先拿到Callable的實例,提到Callable應該會面熟吧,前面的mWorker就是Callable實例,那mWorker如何傳到這的呢?沒錯前面mFuture傳入的mWorker正是此處的mCallabke;
  2. 執行mCallablke的call(),也就是執行mWorker的call(),而mWorker調用了doInbackgroud()和postResult(),到此任務的執行和結果的傳遞都聯繫起來了吧
  3. 最後的set(result)會調用mFuture的done()方法,確認是否傳遞了參數

到此AsyncTask的參數處理、任務執行和結果的傳遞都介紹完畢了,相信你們對此過程應該有所瞭解了,所剩部分就是AsyncTask的線程切換了,前面也提到了是利用Handler實現的,一塊兒看看吧

3.5 線程的切換

  • 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;
            }
        }
    }複製代碼
  • Result的傳遞前面介紹的 postResult()方法中
  • Progress的傳遞調用 publishProgress(Progress... values)
protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }複製代碼

好了,大功告成,全部的內容講完了,有沒有感受代碼封裝的奇妙之處呢?有沒想本身嘗試一下寫一個簡單的AsyncTask呢?心動不如行動,一塊兒實現一個簡單的AsyncTask類吧

四、SimpleAsyncTask

代碼以下:

/**
 * @author  : Alex
 * @date    : 2018/08/25
 * @version : V 2.0.0
 */
const val PROGRESS = 100
const val RESULT = 101
abstract class SimpleAsyncTask<Params, Progress, Result> {

    val handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message?) {
            super.handleMessage(msg)
            when (msg?.what) {
                PROGRESS -> onProgressUpdate(msg.obj as Progress)
                RESULT -> onPostExecute(msg.obj as Result)
            }

        }
    }

    open fun onPreExecute() {

    }

    open abstract fun doInBackground(params: Array<Int>): Result


    open fun onProgressUpdate( progress: Progress) {
    }

    open fun onPostExecute(result: Result) {

    }

    fun postResult(result: Result) {
        val msg = handler.obtainMessage(RESULT, result)
        handler.sendMessage(msg)
    }

    fun publishProgress(progress: Progress) {
        val msg = handler.obtainMessage(PROGRESS, progress)
        handler.sendMessage(msg)
    }

    fun execute(params: Array<Int>) {
        onPreExecute()
        Thread {
            postResult(doInBackground(params))
        }.start()
    }
}複製代碼

將上面例子中改成繼承SimpleAsyncTask,執行結果與AsyncTask執行結果同樣:

例子很是簡單也體現了執行的過程和邏輯,好了本次到此結束。

相關文章
相關標籤/搜索