Android多線程:AsyncTask的原理及其源碼分析

前言

  • AsyncTaskAndroid開發(fā)中是十分常見的
  • 今天,我將全面講解AsyncTask的源碼,希望你們會喜歡

Carson帶你學(xué)多線程系列
基礎(chǔ)匯總
Android多線程:基礎(chǔ)知識匯總
基礎(chǔ)使用
Android多線程:繼承Thread類使用(含實例教程)
Android多線程:實現(xiàn)Runnable接口使用(含實例教程)
復(fù)合使用
Android 多線程:AsyncTask使用教程(含實例講解)
Android 多線程:AsyncTask原理及源碼分析
Android多線程:HandlerThread使用教程(含實例講解)
Android多線程:HandlerThread原理及源碼分析
Android多線程:IntentService使用教程(含實例講解)
Android多線程:IntentService的原理及源碼分析
Android多線程:線程池ThreadPool全方位教學(xué)
相關(guān)使用
Android異步通信:這是一份全面&詳細(xì)的Handler機制學(xué)習(xí)攻略
Android多線程:手把手教你全面學(xué)習(xí)神秘的Synchronized關(guān)鍵字
Android多線程:帶你了解神秘的線程變量 ThreadLocal


目錄

示意圖

1. 簡介

示意圖

更詳細(xì)了解,請看文章:Android 多線程:AsyncTask最詳細(xì)使用教程

本文主要講解其工作原理 & 源碼分析


2. 工作原理

2.1 儲備知識:線程

  • 簡介
示意圖
  • 與進程的區(qū)別
示意圖

2.2 具體原理介紹

  • AsyncTask的實現(xiàn)原理 = 線程池 + Handler

其中:線程池用于線程調(diào)度、復(fù)用 & 執(zhí)行任務(wù);Handler 用于異步通信

  • 其內(nèi)部封裝了2個線程池 + 1個Handler,具體介紹如下:
示意圖

3. 類 & 方法介紹

在進行源碼分析前,先介紹AsyncTask中的類 & 核心方法

3.1 類定義

AsyncTask類屬于抽象類,即使用時需 實現(xiàn)子類

public abstract class AsyncTask<Params, Progress, Result> { 
 ... 
}

// 類中參數(shù)為3種泛型類型
// 整體作用:控制AsyncTask子類執(zhí)行線程任務(wù)時各個階段的返回類型
// 具體說明:
    // a. Params:開始異步任務(wù)執(zhí)行時傳入的參數(shù)類型,對應(yīng)excute()中傳遞的參數(shù)
    // b. Progress:異步任務(wù)執(zhí)行過程中,返回下載進度值的類型
    // c. Result:異步任務(wù)執(zhí)行完成后,返回的結(jié)果類型,與doInBackground()的返回值類型保持一致
// 注:
    // a. 使用時并不是所有類型都被使用
    // b. 若無被使用,可用java.lang.Void類型代替
    // c. 若有不同業(yè)務(wù),需額外再寫1個AsyncTask的子類
}

3.2 核心方法

  • AsyncTask 核心 & 常用的方法如下:
示意圖
  • 方法執(zhí)行順序如下
示意圖

4. 源碼分析

  • 本次源碼分析將根據(jù) AsyncTask的使用步驟講解

若不熟悉,請務(wù)必看文章:Android 多線程:AsyncTask最詳細(xì)使用教程

  • AsyncTask的使用步驟有3個:
  1. 創(chuàng)建 AsyncTask 子類 & 根據(jù)需求實現(xiàn)核心方法
  2. 創(chuàng)建 AsyncTask子類的實例對象(即 任務(wù)實例)
  3. 手動調(diào)用execute(()從而執(zhí)行異步線程任務(wù)
  • 具體介紹如下
/**
  * 步驟1:創(chuàng)建AsyncTask子類
  * 注: 
  *   a. 繼承AsyncTask類
  *   b. 為3個泛型參數(shù)指定類型;若不使用,可用java.lang.Void類型代替
  *   c. 根據(jù)需求,在AsyncTask子類內(nèi)實現(xiàn)核心方法
  */

  private class MyTask extends AsyncTask<Params, Progress, Result> {

        ....

      // 方法1:onPreExecute()
      // 作用:執(zhí)行 線程任務(wù)前的操作
      // 注:根據(jù)需求復(fù)寫
      @Override
      protected void onPreExecute() {
           ...
        }

      // 方法2:doInBackground()
      // 作用:接收輸入?yún)?shù)、執(zhí)行任務(wù)中的耗時操作、返回 線程任務(wù)執(zhí)行的結(jié)果
      // 注:必須復(fù)寫,從而自定義線程任務(wù)
      @Override
      protected String doInBackground(String... params) {

            ...// 自定義的線程任務(wù)

            // 可調(diào)用publishProgress()顯示進度, 之后將執(zhí)行onProgressUpdate()
             publishProgress(count);
              
         }

      // 方法3:onProgressUpdate()
      // 作用:在主線程 顯示線程任務(wù)執(zhí)行的進度
      // 注:根據(jù)需求復(fù)寫
      @Override
      protected void onProgressUpdate(Integer... progresses) {
            ...

        }

      // 方法4:onPostExecute()
      // 作用:接收線程任務(wù)執(zhí)行結(jié)果、將執(zhí)行結(jié)果顯示到UI組件
      // 注:必須復(fù)寫,從而自定義UI操作
      @Override
      protected void onPostExecute(String result) {

         ...// UI操作

        }

      // 方法5:onCancelled()
      // 作用:將異步任務(wù)設(shè)置為:取消狀態(tài)
      @Override
        protected void onCancelled() {
        ...
        }
  }

/**
  * 步驟2:創(chuàng)建AsyncTask子類的實例對象(即 任務(wù)實例)
  * 注:AsyncTask子類的實例必須在UI線程中創(chuàng)建
  */
  MyTask mTask = new MyTask();

/**
  * 步驟3:手動調(diào)用execute(Params... params) 從而執(zhí)行異步線程任務(wù)
  * 注:
  *    a. 必須在UI線程中調(diào)用
  *    b. 同一個AsyncTask實例對象只能執(zhí)行1次,若執(zhí)行第2次將會拋出異常
  *    c. 執(zhí)行任務(wù)中,系統(tǒng)會自動調(diào)用AsyncTask的一系列方法:onPreExecute() 、doInBackground()、onProgressUpdate() 、onPostExecute() 
  *    d. 不能手動調(diào)用上述方法
  */
  mTask.execute();

  • 下面,我將根據(jù)上述使用步驟進行源碼分析

步驟1:創(chuàng)建AsyncTask子類

在該步驟中,只需知道 “該類中復(fù)寫的方法將在后續(xù)源碼中調(diào)用” 即可

步驟2:創(chuàng)建AsyncTask子類的實例對象(即 任務(wù)實例)

/**
  * 具體使用
  */
  MyTask mTask = new MyTask();

/**
  * 源碼分析:AsyncTask的構(gòu)造函數(shù)
  */
  public AsyncTask() {
        // 1. 初始化WorkerRunnable變量 = 一個可存儲參數(shù)的Callable對象 ->>分析1
        mWorker = new WorkerRunnable<Params, Result>() {
            // 在任務(wù)執(zhí)行線程池中回調(diào):THREAD_POOL_EXECUTOR.execute()
            // 下面會詳細(xì)講解
            public Result call() throws Exception {

                // 添加線程的調(diào)用標(biāo)識
                mTaskInvoked.set(true); 

                Result result = null;
                try {
                    // 設(shè)置線程的優(yōu)先級
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    
                    // 執(zhí)行異步操作 = 耗時操作
                    // 即 我們使用過程中復(fù)寫的耗時任務(wù)
                    result = doInBackground(mParams);

                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    
                    mCancelled.set(true);// 若運行異常,設(shè)置取消的標(biāo)志
                    throw tr;
                } finally {
                    
                    // 把異步操作執(zhí)行的結(jié)果發(fā)送到主線程
                    // 從而更新UI,下面會詳細(xì)講解
                    postResult(result); 
                }
                return result;
            }
        };

        // 2. 初始化FutureTask變量 = 1個FutureTask ->>分析2
        mFuture = new FutureTask<Result>(mWorker) {

            // done()簡介:FutureTask內(nèi)的Callable執(zhí)行完后的調(diào)用方法
            // 作用:復(fù)查任務(wù)的調(diào)用、將未被調(diào)用的任務(wù)的結(jié)果通過InternalHandler傳遞到UI線程
            @Override
            protected void done() {
                try {

                    // 在執(zhí)行完任務(wù)后檢查,將沒被調(diào)用的Result也一并發(fā)出 ->>分析3
                    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) {

                    //若 發(fā)生異常,則將發(fā)出null
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

/**
  * 分析1:WorkerRunnable類的構(gòu)造函數(shù)
  */
  private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        // 此處的Callable也是任務(wù);
        // 與Runnable的區(qū)別:Callable<T>存在返回值 = 其泛型
        Params[] mParams;
    }

/**
  * 分析2:FutureTask類的構(gòu)造函數(shù)
  * 定義:1個包裝任務(wù)的包裝類
  * 注:內(nèi)部包含Callable<T> 、增加了一些狀態(tài)標(biāo)識 & 操作Callable<T>的接口
  */
  public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;      
    }
    // 回到調(diào)用原處

/**
  * 分析3:postResultIfNotInvoked()
  */
  private void postResultIfNotInvoked()(Result result) {
        // 取得任務(wù)標(biāo)記
        final boolean wasTaskInvoked = mTaskInvoked.get();

        // 若任務(wù)無被執(zhí)行,將未被調(diào)用的任務(wù)的結(jié)果通過InternalHandler傳遞到UI線程
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

總結(jié):

  • 創(chuàng)建了1個WorkerRunnable類 的實例對象 & 復(fù)寫了call()方法
  • 創(chuàng)建了1個FutureTask類 的實例對象 & 復(fù)寫了 done()

步驟3:手動調(diào)用execute(Params... params)

/**
  * 具體使用
  */
  mTask.execute();

/**
  * 源碼分析:AsyncTask的execute()
  */
  public final AsyncTask<Params, Progress, Result> execute(Params... params) {

        return executeOnExecutor(sDefaultExecutor, params);
        // ->>分析1

    }

 /**
  * 分析1:executeOnExecutor(sDefaultExecutor, params)
  * 參數(shù)說明:sDefaultExecutor = 任務(wù)隊列 線程池類(SerialExecutor)的對象
  */
  public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) {

        // 1. 判斷 AsyncTask 當(dāng)前的執(zhí)行狀態(tài)
        // PENDING = 初始化狀態(tài)
        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)");
            }
        }

        // 2. 將AsyncTask狀態(tài)設(shè)置為RUNNING狀態(tài)
        mStatus = Status.RUNNING;

        // 3. 主線程初始化工作
        onPreExecute();

        // 4. 添加參數(shù)到任務(wù)中
        mWorker.mParams = params;

        // 5. 執(zhí)行任務(wù)
        // 此處的exec = sDefaultExecutor = 任務(wù)隊列 線程池類(SerialExecutor)的對象
        // ->>分析2
        exec.execute(mFuture);
        return this;
    }

/**
  * 分析2:exec.execute(mFuture)
  * 說明:屬于任務(wù)隊列 線程池類(SerialExecutor)的方法
  */
  private static class SerialExecutor implements Executor {
        // SerialExecutor = 靜態(tài)內(nèi)部類
        // 即 是所有實例化的AsyncTask對象公有的

        // SerialExecutor 內(nèi)部維持了1個雙向隊列;
        // 容量根據(jù)元素數(shù)量調(diào)節(jié)
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        // execute()被同步鎖synchronized修飾
        // 即說明:通過鎖使得該隊列保證AsyncTask中的任務(wù)是串行執(zhí)行的
        // 即 多個任務(wù)需1個個加到該隊列中;然后 執(zhí)行完隊列頭部的再執(zhí)行下一個,以此類推
        public synchronized void execute(final Runnable r) {
            // 將實例化后的FutureTask類 的實例對象傳入
            // 即相當(dāng)于:向隊列中加入一個新的任務(wù)
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();->>分析3
                    }
                }
            });
            // 若當(dāng)前無任務(wù)執(zhí)行,則去隊列中取出1個執(zhí)行
            if (mActive == null) {
                scheduleNext();
            }
        }
        // 分析3
        protected synchronized void scheduleNext() {
            // 1. 取出隊列頭部任務(wù)
            if ((mActive = mTasks.poll()) != null) {

                // 2. 執(zhí)行取出的隊列頭部任務(wù)
                // 即 調(diào)用執(zhí)行任務(wù)線程池類(THREAD_POOL_EXECUTOR)->>繼續(xù)往下看
                THREAD_POOL_EXECUTOR.execute(mActive);
                
            }
        }
    }

總結(jié):

  • 執(zhí)行任務(wù)前,通過 任務(wù)隊列 線程池類(SerialExecutor)將任務(wù)按順序放入到隊列中;

通過同步鎖 修飾execute()從而保證AsyncTask中的任務(wù)是串行執(zhí)行的

  • 之后的線程任務(wù)執(zhí)行是 通過任務(wù)線程池類(THREAD_POOL_EXECUTOR) 進行的。

繼續(xù)往下分析:THREAD_POOL_EXECUTOR.execute()

/**
  * 源碼分析:THREAD_POOL_EXECUTOR.execute()
  * 說明:
  *     a. THREAD_POOL_EXECUTOR實際上是1個已配置好的可執(zhí)行并行任務(wù)的線程池
  *     b. 調(diào)用THREAD_POOL_EXECUTOR.execute()實際上是調(diào)用線程池的execute()去執(zhí)行具體耗時任務(wù)
  *     c. 而該耗時任務(wù)則是步驟2中初始化WorkerRunnable實例對象時復(fù)寫的call()
  * 注:下面先看任務(wù)執(zhí)行線程池的線程配置過程,看完后請回到步驟2中的源碼分析call()
  */

    // 步驟1:參數(shù)設(shè)置
        //獲得當(dāng)前CPU的核心數(shù)
        private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
        //設(shè)置線程池的核心線程數(shù)2-4之間,但是取決于CPU核數(shù)
        private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
        //設(shè)置線程池的最大線程數(shù)為 CPU核數(shù)*2+1
        private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
        //設(shè)置線程池空閑線程存活時間30s
        private static final int KEEP_ALIVE_SECONDS = 30;

        //初始化線程工廠
        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());
            }
        };

        //初始化存儲任務(wù)的隊列為LinkedBlockingQueue 最大容量為128
        private static final BlockingQueue<Runnable> sPoolWorkQueue =
                new LinkedBlockingQueue<Runnable>(128);

    // 步驟2: 根據(jù)參數(shù)配置執(zhí)行任務(wù)線程池,即 THREAD_POOL_EXECUTOR
    public static final Executor THREAD_POOL_EXECUTOR;

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        // 設(shè)置核心線程池的 超時時間也為30s
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

    // 請回到步驟2中的源碼分析call()

至此,我們回到步驟2中的源碼分析call()

/**
  * 步驟2的源碼分析:AsyncTask的構(gòu)造函數(shù)
  */
    public AsyncTask() {
        // 1. 初始化WorkerRunnable變量 = 一個可存儲參數(shù)的Callable對象
        mWorker = new WorkerRunnable<Params, Result>() {

            public Result call() throws Exception {

                // 添加線程的調(diào)用標(biāo)識
                mTaskInvoked.set(true); 

                Result result = null;
                try {
                    // 設(shè)置線程的優(yōu)先級
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    
                    // 執(zhí)行異步操作 = 耗時操作
                    // 即 我們使用過程中復(fù)寫的耗時任務(wù)
                    result = doInBackground(mParams);

                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    
                    mCancelled.set(true);// 若運行異常,設(shè)置取消的標(biāo)志
                    throw tr;
                } finally {
                    
                    // 把異步操作執(zhí)行的結(jié)果發(fā)送到主線程
                    // 從而更新UI ->>分析1
                    postResult(result); 
                }
                return result;
            }
        };

        .....// 省略
    }
/**
  * 分析1:postResult(result)
  */
   private Result postResult(Result result) {

        @SuppressWarnings("unchecked")

        // 創(chuàng)建Handler對象 ->> 源自InternalHandler類—>>分析2
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        // 發(fā)送消息到Handler中
        message.sendToTarget();
        return result;

    }


/**
  * 分析2:InternalHandler類
  */
    private static class InternalHandler extends Handler {

        // 構(gòu)造函數(shù)
        public InternalHandler() {
            super(Looper.getMainLooper());
            // 獲取的是主線程的Looper()
            // 故 AsyncTask的實例創(chuàng)建 & execute()必須在主線程使用
        }

        @Override
        public void handleMessage(Message msg) {

            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;

            switch (msg.what) {
                // 若收到的消息 = MESSAGE_POST_RESULT
                // 則通過finish() 將結(jié)果通過Handler傳遞到主線程
                case MESSAGE_POST_RESULT:
                    result.mTask.finish(result.mData[0]); ->>分析3
                    break;

                // 若收到的消息 = MESSAGE_POST_PROGRESS
                // 則回調(diào)onProgressUpdate()通知主線程更新進度的操作
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
/**
  * 分析3:result.mTask.finish(result.mData[0])
  */
  private void finish(Result result) {
        // 先判斷是否調(diào)用了Cancelled()
            // 1. 若調(diào)用了則執(zhí)行我們復(fù)寫的onCancelled()
            // 即 取消任務(wù)時的操作
            if (isCancelled()) {
                onCancelled(result);
            } else {

            // 2. 若無調(diào)用Cancelled(),則執(zhí)行我們復(fù)寫的onPostExecute(result)
            // 即更新UI操作
                onPostExecute(result);
            }
            // 注:不管AsyncTask是否被取消,都會將AsyncTask的狀態(tài)變更為:FINISHED
            mStatus = Status.FINISHED;
        }

總結(jié)

  • 任務(wù)線程池類(THREAD_POOL_EXECUTOR)實際上是1個已配置好的可執(zhí)行并行任務(wù)的線程池
  • 調(diào)用THREAD_POOL_EXECUTOR.execute()實際上是調(diào)用線程池的execute()去執(zhí)行具體耗時任務(wù)
  • 而該耗時任務(wù)則是步驟2中初始化 WorkerRunnable實例對象時復(fù)寫的call()內(nèi)容
  • call()方法里,先調(diào)用 我們復(fù)寫的doInBackground(mParams)執(zhí)行耗時操作
  • 再調(diào)用postResult(result), 通過 InternalHandler 類 將任務(wù)消息傳遞到主線程;根據(jù)消息標(biāo)識(MESSAGE_POST_RESULT)判斷,最終通過finish()調(diào)用我們復(fù)寫的onPostExecute(result),從而實現(xiàn)UI更新操作

至此,關(guān)于AsyncTask的源碼 分析完畢,附上一份最終總結(jié):

示意圖

9. 總結(jié)

  • 本文介紹了多線程中的AsyncTask的 工作原理 & 源碼分析,總結(jié)如下:
示意圖
示意圖
  • 下一篇文章我將對講解Android多線程的相關(guān)知識,感興趣的同學(xué)可以繼續(xù)關(guān)注Carson_Ho的簡書

Carson帶你學(xué)多線程系列
基礎(chǔ)匯總
Android多線程:基礎(chǔ)知識匯總
基礎(chǔ)使用
Android多線程:繼承Thread類使用(含實例教程)
Android多線程:實現(xiàn)Runnable接口使用(含實例教程)
復(fù)合使用
Android 多線程:AsyncTask使用教程(含實例講解)
Android 多線程:AsyncTask原理及源碼分析
Android多線程:HandlerThread使用教程(含實例講解)
Android多線程:HandlerThread原理及源碼分析
Android多線程:IntentService使用教程(含實例講解)
Android多線程:IntentService的原理及源碼分析
Android多線程:線程池ThreadPool全方位教學(xué)
相關(guān)使用
Android異步通信:這是一份全面&詳細(xì)的Handler機制學(xué)習(xí)攻略
Android多線程:手把手教你全面學(xué)習(xí)神秘的Synchronized關(guān)鍵字
Android多線程:帶你了解神秘的線程變量 ThreadLocal


歡迎關(guān)注Carson_Ho的簡書

不定期分享關(guān)于安卓開發(fā)的干貨,追求短、平、快,但卻不缺深度。


請點贊!因為你的鼓勵是我寫作的最大動力!

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

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

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