Android Handler機(jī)制13之AsyncTask源碼解析

Android Handler機(jī)制系列文章整體內(nèi)容如下:

本篇文章的主要內(nèi)容如下:

  • 1法挨、AsyncTask概述
  • 2初厚、基本用法
  • 3峭弟、AsyncTask類源碼解析
  • 4闷畸、AsyncTask類的構(gòu)造函數(shù)
  • 5腰耙、AsyncTask類核心方法解析
  • 6杠园、AsyncTask核心流程
  • 7、AsyncTask與Handler

AsyncTask官網(wǎng)
AsyncTask源碼

一掷邦、AsyncTask概述

我們都知道,Android UI線程是不安全的椭赋,如果想要在子線程里面進(jìn)行UI操作抚岗,就需要直接Android的異步消息處理機(jī)制,前面我寫了很多文章從源碼層面分析了Android異步消息Handler的處理機(jī)制哪怔。感興趣的可以去了解下宣蔚。不過為了更方便我們?cè)谧泳€程中更新UI元素,Android1.5版本就引入了一個(gè)AsyncTask類认境,使用它就可以非常靈活方便地從子線程切換到UI線程胚委。

二、基本用法

AsyncTask是一個(gè)抽象類叉信,我們需要?jiǎng)?chuàng)建子類去繼承它篷扩,并且重寫一些方法。AsyncTask接受三個(gè)泛型的參數(shù):

  • Params:指定傳給任務(wù)執(zhí)行時(shí)的參數(shù)的類型
  • Progress:指定后臺(tái)任務(wù)執(zhí)行時(shí)將任務(wù)進(jìn)度返回給UI線程的參數(shù)類型
  • Result:指定任務(wù)完成后返回的結(jié)果類型

除了指定泛型參數(shù)茉盏,還需要根據(jù)重寫一些方法鉴未,常用的如下:

  • onPreExecute():這個(gè)方法在UI線程調(diào)用,用于在任務(wù)執(zhí)行器那做一些初始化操作鸠姨,如在界面上顯示加載進(jìn)度空間
  • onInBackground:在onPreExecute()結(jié)束之后立刻在后臺(tái)線程調(diào)用铜秆,用于耗時(shí)操作。在這個(gè)方法中可調(diào)用publishProgress方法返回任務(wù)的執(zhí)行進(jìn)度讶迁。
  • onProgressUpdate:在doInBackground調(diào)用publishProgress后被調(diào)用连茧,工作在UI線程
  • onPostExecute:后臺(tái)任務(wù)結(jié)束后被調(diào)用,工作在UI線程巍糯。

三啸驯、AsyncTask類源碼解析

AsyncTask.java源碼地址

(一)、類注釋翻譯

源碼注釋如下:

/**
 * <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>
 *
 * <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
 * and does not constitute a generic threading framework. AsyncTasks should ideally be
 * used for short operations (a few seconds at the most.) If you need to keep threads
 * running for long periods of time, it is highly recommended you use the various APIs
 * provided by the <code>java.util.concurrent</code> package such as {@link Executor},
 * {@link ThreadPoolExecutor} and {@link FutureTask}.</p>
 *
 * <p>An asynchronous task is defined by a computation that runs on a background thread and
 * whose result is published on the UI thread. An asynchronous task is defined by 3 generic
 * types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
 * and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>,
 * <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p>
 *
 * <div class="special reference">
 * <h3>Developer Guides</h3>
 * <p>For more information about using tasks and threads, read the
 * <a href="{@docRoot}guide/components/processes-and-threads.html">Processes and
 * Threads</a> developer guide.</p>
 * </div>
 *
 * <h2>Usage</h2>
 * <p>AsyncTask must be subclassed to be used. The subclass will override at least
 * one method ({@link #doInBackground}), and most often will override a
 * second one ({@link #onPostExecute}.)</p>
 *
 * <p>Here is an example of subclassing:</p>
 * <pre class="prettyprint">
 * private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
 *     protected Long doInBackground(URL... urls) {
 *         int count = urls.length;
 *         long totalSize = 0;
 *         for (int i = 0; i < count; i++) {
 *             totalSize += Downloader.downloadFile(urls[i]);
 *             publishProgress((int) ((i / (float) count) * 100));
 *             // Escape early if cancel() is called
 *             if (isCancelled()) break;
 *         }
 *         return totalSize;
 *     }
 *
 *     protected void onProgressUpdate(Integer... progress) {
 *         setProgressPercent(progress[0]);
 *     }
 *
 *     protected void onPostExecute(Long result) {
 *         showDialog("Downloaded " + result + " bytes");
 *     }
 * }
 * </pre>
 *
 * <p>Once created, a task is executed very simply:</p>
 * <pre class="prettyprint">
 * new DownloadFilesTask().execute(url1, url2, url3);
 * </pre>
 *
 * <h2>AsyncTask's generic types</h2>
 * <p>The three types used by an asynchronous task are the following:</p>
 * <ol>
 *     <li><code>Params</code>, the type of the parameters sent to the task upon
 *     execution.</li>
 *     <li><code>Progress</code>, the type of the progress units published during
 *     the background computation.</li>
 *     <li><code>Result</code>, the type of the result of the background
 *     computation.</li>
 * </ol>
 * <p>Not all types are always used by an asynchronous task. To mark a type as unused,
 * simply use the type {@link Void}:</p>
 * <pre>
 * private class MyTask extends AsyncTask<Void, Void, Void> { ... }
 * </pre>
 *
 * <h2>The 4 steps</h2>
 * <p>When an asynchronous task is executed, the task goes through 4 steps:</p>
 * <ol>
 *     <li>{@link #onPreExecute()}, invoked on the UI thread before the task
 *     is executed. This step is normally used to setup the task, for instance by
 *     showing a progress bar in the user interface.</li>
 *     <li>{@link #doInBackground}, invoked on the background thread
 *     immediately after {@link #onPreExecute()} finishes executing. This step is used
 *     to perform background computation that can take a long time. The parameters
 *     of the asynchronous task are passed to this step. The result of the computation must
 *     be returned by this step and will be passed back to the last step. This step
 *     can also use {@link #publishProgress} to publish one or more units
 *     of progress. These values are published on the UI thread, in the
 *     {@link #onProgressUpdate} step.</li>
 *     <li>{@link #onProgressUpdate}, invoked on the UI thread after a
 *     call to {@link #publishProgress}. The timing of the execution is
 *     undefined. This method is used to display any form of progress in the user
 *     interface while the background computation is still executing. For instance,
 *     it can be used to animate a progress bar or show logs in a text field.</li>
 *     <li>{@link #onPostExecute}, invoked on the UI thread after the background
 *     computation finishes. The result of the background computation is passed to
 *     this step as a parameter.</li>
 * </ol>
 * 
 * <h2>Cancelling a task</h2>
 * <p>A task can be cancelled at any time by invoking {@link #cancel(boolean)}. Invoking
 * this method will cause subsequent calls to {@link #isCancelled()} to return true.
 * After invoking this method, {@link #onCancelled(Object)}, instead of
 * {@link #onPostExecute(Object)} will be invoked after {@link #doInBackground(Object[])}
 * returns. To ensure that a task is cancelled as quickly as possible, you should always
 * check the return value of {@link #isCancelled()} periodically from
 * {@link #doInBackground(Object[])}, if possible (inside a loop for instance.)</p>
 *
 * <h2>Threading rules</h2>
 * <p>There are a few threading rules that must be followed for this class to
 * work properly:</p>
 * <ul>
 *     <li>The AsyncTask class must be loaded on the UI thread. This is done
 *     automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.</li>
 *     <li>The task instance must be created on the UI thread.</li>
 *     <li>{@link #execute} must be invoked on the UI thread.</li>
 *     <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
 *     {@link #doInBackground}, {@link #onProgressUpdate} manually.</li>
 *     <li>The task can be executed only once (an exception will be thrown if
 *     a second execution is attempted.)</li>
 * </ul>
 *
 * <h2>Memory observability</h2>
 * <p>AsyncTask guarantees that all callback calls are synchronized in such a way that the following
 * operations are safe without explicit synchronizations.</p>
 * <ul>
 *     <li>Set member fields in the constructor or {@link #onPreExecute}, and refer to them
 *     in {@link #doInBackground}.
 *     <li>Set member fields in {@link #doInBackground}, and refer to them in
 *     {@link #onProgressUpdate} and {@link #onPostExecute}.
 * </ul>
 *
 * <h2>Order of execution</h2>
 * <p>When first introduced, AsyncTasks were executed serially on a single background
 * thread. Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
 * to a pool of threads allowing multiple tasks to operate in parallel. Starting with
 * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are executed on a single
 * thread to avoid common application errors caused by parallel execution.</p>
 * <p>If you truly want parallel execution, you can invoke
 * {@link #executeOnExecutor(java.util.concurrent.Executor, Object[])} with
 * {@link #THREAD_POOL_EXECUTOR}.</p>
 */

簡(jiǎn)單翻譯一下:

  • AsyncTask可以輕松的正確使用UI線程祟峦,該類允許你執(zhí)行后臺(tái)操作并在UI線程更新結(jié)果罚斗,從而避免了無需使用Handler來操作線程
  • AsyncTask是圍繞Thread與Handler而設(shè)計(jì)的輔助類,所以它并不是一個(gè)通用的線程框架宅楞。理想情況下针姿,AsyncTask應(yīng)該用于短操作(最多幾秒)。如果你的需求是在長(zhǎng)時(shí)間保持線程運(yùn)行厌衙,強(qiáng)烈建議您使用由
    java.util.concurrent提供的各種API包距淫,比如Executor、ThreadPoolExecutor或者FutureTask婶希。
  • 一個(gè)異步任務(wù)被定義為:在后臺(tái)線程上運(yùn)行榕暇,并在UI線程更新結(jié)果。一個(gè)異步任務(wù)通常由三個(gè)類型:Params、Progress和Result彤枢。以及4個(gè)步驟:onPreExecute撤蟆、doInBackground、onProgressUpdate堂污、onPostExecute。
  • 用法:AsyncTask必須由子類實(shí)現(xiàn)后才能使用龄砰,它的子類至少重寫doInBackground()這個(gè)方法盟猖,并且通常也會(huì)重寫onPostExecute()這個(gè)方法
  • 下面是一個(gè)繼承AsyncTask類的一個(gè)子類的例子
   private class DownloadFilesTask extends AsyncTask<URL, >Integer, Long>
   {
       protected Long doInBackground(URL... urls) {
           int count = urls.length;
           long totalSize = 0;
           for (int i = 0; i < count; i++) {
               totalSize += Downloader.downloadFile(urls[i]);
               publishProgress((int) ((i / (float) count) * 100));
               // Escape early if cancel() is called
               if (isCancelled()) break;
           }
           return totalSize;
       }

       protected void onProgressUpdate(Integer... progress) {
           setProgressPercent(progress[0]);
       }

       protected void onPostExecute(Long result) {
           showDialog("Downloaded " + result + " bytes");
       }
   }

一旦創(chuàng)建,任務(wù)會(huì)被很輕松的執(zhí)行换棚。就像下面這塊代碼一樣

new DownloadFilesTask().execute(url1,url2,url3);
  • AsyncTask泛型式镐,在異步任務(wù)中通常有三個(gè)泛型
    • Params:發(fā)送給任務(wù)的參數(shù)類型,這個(gè)類型會(huì)被任務(wù)執(zhí)行
    • Progress:后臺(tái)線程進(jìn)度的計(jì)算的基本單位固蚤。
    • Result:后臺(tái)線程執(zhí)行的結(jié)果類型娘汞。
  • 如果異步任務(wù)不需要上面類型,則可以需要聲明類型未使用夕玩,通過使用Void來表示類型未使用你弦。就像下面一楊
private class MyTask extends AsyncTask<Void, Void, Void>{...}
  • 四個(gè)步驟
    • onPreExecute() 在執(zhí)行任務(wù)之前在UI線程上調(diào)用,此步驟通常用于初始化任務(wù)燎孟,例如在用戶界面顯示進(jìn)度條禽作。
    • doInBackground() 方法在 onPreExecute()執(zhí)行完成后調(diào)用的。doInBackground()這個(gè)方法用于執(zhí)行可能需要很長(zhǎng)時(shí)間的首臺(tái)計(jì)算揩页。異步任務(wù)的參數(shù)被傳遞到這個(gè)步驟中旷偿。計(jì)算結(jié)果必須經(jīng)由這個(gè)步驟返回。這個(gè)步驟內(nèi)還可以調(diào)用publishProgress()方法發(fā)布一個(gè)或者多個(gè)進(jìn)度單位爆侣。在調(diào)用onProgressUpdate()函數(shù)后萍程,這個(gè)結(jié)果將在UI線程上更新。
    • onProgressUpdate()方法:在調(diào)用publishProgress()之后在UI線程上調(diào)用兔仰。具體的執(zhí)行時(shí)間不確定茫负,該方法用于在后臺(tái)計(jì)算的異步任務(wù),把具體的進(jìn)度顯示在用戶界面乎赴。例如朽褪,它可以用于對(duì)進(jìn)度條進(jìn)行動(dòng)畫處理或者在文本字段中顯示日志。
    • onPostExecute()方法无虚, 后臺(tái)任務(wù)完成后缔赠,在UI線程調(diào)用onPostExecute()方法,后臺(tái)運(yùn)行的結(jié)果作為參數(shù)傳遞給這個(gè)方法
  • 取消任務(wù)
    在任何時(shí)候都可以通過調(diào)用cancel(boolean)來取消任務(wù)友题。調(diào)用此方法將導(dǎo)致isCancelled()方法的后續(xù)調(diào)用返回true嗤堰。調(diào)用此方法后,在執(zhí)行doInBackground(Object [])方法后,將調(diào)用onCancelled(object)踢匣,而不是onPostExecute(Object)方法告匠。為了盡可能快的取消任務(wù),如果可能的話离唬,你應(yīng)該在調(diào)用doInBackground(Object[])之前檢查isCancelled()的返回值后专。
  • 線程規(guī)則,這個(gè)類必須遵循有關(guān)線程的一些規(guī)則才能正常使用输莺,規(guī)則如下:
    • 必須在UI線程上加載AsyncTask類戚哎,android4.1上自動(dòng)完成
    • 任務(wù)實(shí)例必須在UI線程上實(shí)例化
    • execute()方法必須在主線程上調(diào)用
    • 不要手動(dòng)去調(diào)用onPreExecute()、onPostExecute()嫂用、doInBackground()型凳、onProgressUpdate()方法。
    • 這個(gè)任務(wù)只能執(zhí)行一次(如果嘗試第二次執(zhí)行嘱函,將會(huì)拋出異常)甘畅。
      該任務(wù)只能執(zhí)行一次(如果嘗試第二次執(zhí)行,將拋出異常)往弓。
  • 內(nèi)存的觀察AsyncTask疏唾。保證所有回調(diào)調(diào)用都是同步的,使得以下操作在沒有顯示同步情況下是安全的函似。
    • 在構(gòu)造函數(shù)或者onPreExecute設(shè)置成員變量荸实,并且在doInBackground()方法中引用它們。
    • 在doInBackground()設(shè)置成員字段缴淋,并在onProgressUpdate()和onPostExecute()方法中引用他們准给。
  • 執(zhí)行順序。第一引入AsyncTask時(shí)重抖,AsyncTasks是在單個(gè)后臺(tái)線程串行執(zhí)行的露氮。在android1.6以后,這被更改為允許多個(gè)任務(wù)并行操作的線程池钟沛。從android 3.0開始畔规,每個(gè)任務(wù)都是執(zhí)行在一個(gè)獨(dú)立的線程上,這樣可以避免一些并行執(zhí)行引起的常見的應(yīng)用程序錯(cuò)誤恨统。如果你想要并行執(zhí)行叁扫,可以使用THREAD_POOL_EXECUTOR來調(diào)用executeOnExecutor()方法。

至此這個(gè)類的注釋翻譯完畢畜埋,好長(zhǎng)啊莫绣,大家看完翻譯,是不是發(fā)現(xiàn)了很多之前沒有考慮到的問題悠鞍。

(二)对室、AsyncTask的結(jié)構(gòu)

AsyncTask的結(jié)構(gòu)如下:

AsyncTask的結(jié)構(gòu).png

我們看到在AsyncTask有4個(gè)自定義類,一個(gè)枚舉類,一個(gè)靜態(tài)塊掩宜,然后才是這個(gè)類的具體變量和屬性蔫骂,那我們就依次講解

(三)、枚舉Status

代碼在AsyncTask.java 256行

    /**
     * Indicates the current status of the task. Each status will be set only once
     * during the lifetime of a task.
     */
   
    public enum Status {
        /**
         * Indicates that the task has not been executed yet.
         */
        PENDING,
        /**
         * Indicates that the task is running.
         */
        RUNNING,
        /**
         * Indicates that {@link AsyncTask#onPostExecute} has finished.
         */
        FINISHED,
    }

枚舉Status上的注釋翻譯一下就是:

Status表示當(dāng)前任務(wù)的狀態(tài)牺汤,每種狀態(tài)只能在任務(wù)的生命周期內(nèi)設(shè)置一次辽旋。

所以任務(wù)有三種狀態(tài)

  • PENDING:表示任務(wù)尚未執(zhí)行的狀態(tài)
  • RUNNING:表示任務(wù)正在執(zhí)行
  • FINISHED:任務(wù)已完成

(四)、私有的靜態(tài)類InternalHandler

代碼在AsyncTask.java 656行

    private static class InternalHandler extends Handler {
        public InternalHandler() {
            // 這個(gè)handler是關(guān)聯(lián)到主線程的
            super(Looper.getMainLooper());
        }

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

通過上面的代碼我們知道:

  • InternalHandler繼承自Handler檐迟,并且在它的構(gòu)造函數(shù)里面調(diào)用了Looper.getMainLooper()补胚,所以我們知道這個(gè)Handler是關(guān)聯(lián)主線程的。
  • 重寫了handleMessage(Message)方法锅减,其中這個(gè)Message的obj這個(gè)類型是AsyncTaskResult(AsyncTaskResult我將在下面講解),然后根據(jù)msg.what的來區(qū)別伐坏。
  • 我們知道這個(gè)Message只有兩個(gè)標(biāo)示怔匣,一個(gè)是MESSAGE_POST_RESULT代表消息的結(jié)果,一個(gè)是MESSAGE_POST_PROGRESS代表要執(zhí)行onProgressUpdate()方法桦沉。

通過這段代碼我們可以推測(cè)AsyncTask內(nèi)部實(shí)現(xiàn)線程切換每瞒,即切換到主線程是通過Handler來實(shí)現(xiàn)的。

(五)纯露、私有的靜態(tài)類AsyncTaskResult

代碼在AsyncTask.java 682行

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

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

通過類名剿骨,我們大概可以推測(cè)出這一個(gè)負(fù)責(zé)AsyncTask結(jié)果的類

AsyncTaskResult這個(gè)類 有兩個(gè)成員變量,一個(gè)是AsyncTask一個(gè)是泛型的數(shù)組埠褪。

  • mTask參數(shù):是為了AsyncTask是方便在handler的handlerMessage回調(diào)中方便調(diào)用AsyncTask的本身回調(diào)函數(shù)浓利,比如onPostExecute()函數(shù)、onPreogressUpdata()函數(shù)钞速,所以在AsyncTaskResult需要持有AsyncTask贷掖。
  • mData參數(shù):既然是代表結(jié)果,那么肯定要有一個(gè)變量持有這個(gè)計(jì)算結(jié)果

(六)渴语、私有靜態(tài)抽象類WorkerRunnable

代碼在AsyncTask.java 677行

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

這個(gè)抽象類很簡(jiǎn)答苹威,首先是實(shí)現(xiàn)了Callable接口,然后里面有個(gè)變量
mParams驾凶,類型是泛型傳進(jìn)來的數(shù)組

(七)牙甫、局部變量詳解

AsyncTask的局部變量如下:

    private static final String LOG_TAG = "AsyncTask";

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // We want at least 2 threads and at most 4 threads in the core pool,
    // preferring to have 1 less than the CPU count to avoid saturating
    // the CPU with background work
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    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());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR;


    /**
     * An {@link Executor} that executes tasks one at a time in serial
     * order.  This serialization is global to a particular process.
     */
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    private static InternalHandler sHandler;

    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;

    private volatile Status mStatus = Status.PENDING;
    
    private final AtomicBoolean mCancelled = new AtomicBoolean();
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

那我們就來一一解答

  • String LOG_TAG = "AsyncTask":打印專用
  • CPU_COUNT = Runtime.getRuntime().availableProcessors():獲取當(dāng)前CPU的核心數(shù)
  • CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)):線程池的核心容量,通過代碼我們知道是一個(gè)大于等于2小于等于4的數(shù)
  • MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1:線程池的最大容量是2倍的CPU核心數(shù)+1
  • KEEP_ALIVE_SECONDS = 30:過剩的空閑線程的存活時(shí)間调违,一般是30秒
  • sThreadFactory:線程工廠窟哺,通過new Thread來獲取新線程,里面通過使用AtomicInteger原子整數(shù)保證超高并發(fā)下可以正常工作技肩。
  • sPoolWorkQueue:靜態(tài)阻塞式隊(duì)列脏答,用來存放待執(zhí)行的任務(wù),初始容量:128個(gè)
  • THREAD_POOL_EXECUTOR:線程池
  • SERIAL_EXECUTOR = new SerialExecutor():靜態(tài)串行任務(wù)執(zhí)行器,其內(nèi)部實(shí)現(xiàn)了串行控制殖告,循環(huán)的取出一個(gè)個(gè)任務(wù)交給上述的并發(fā)線程池去執(zhí)行阿蝶。
  • MESSAGE_POST_RESULT = 0x1:消息類型,代表發(fā)送結(jié)果
  • MESSAGE_POST_PROGRESS = 0x2:消息類型黄绩,代表進(jìn)度
  • sDefaultExecutor = SERIAL_EXECUTOR:默認(rèn)任務(wù)執(zhí)行器羡洁,被賦值為串行任務(wù)執(zhí)行器,就是因?yàn)樗ぃ珹syncTask變成了串行的了筑煮。
  • sHandler:靜態(tài)Handler,用來發(fā)送上面的兩種通知粤蝎,采用UI線程的Looper來處理消息真仲,這就是為什么AnsyncTask可以在UI線程更新UI
  • WorkerRunnable<Params, Result> mWorke:是一個(gè)實(shí)現(xiàn)Callback的抽象類,擴(kuò)展了Callable多了一個(gè)Params參數(shù)初澎。
  • mFuture:FutureTask對(duì)象
  • mStatus = Status.PENDING:任務(wù)的狀態(tài)默認(rèn)為掛起秸应,即等待執(zhí)行,其類型標(biāo)示為volatile
  • mCancelled = new AtomicBoolean():原子布爾類型碑宴,支持高并發(fā)訪問软啼,標(biāo)示任務(wù)是否被取消
  • mTaskInvoked = new AtomicBoolean():原子布爾類型,支持高并發(fā)訪問延柠,標(biāo)示任務(wù)是否被執(zhí)行過

(八)祸挪、靜態(tài)代碼塊

代碼在AsyncTask.java 226行

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

通過上面的(七)、局部變量詳解贞间,我們知道在靜態(tài)代碼塊中創(chuàng)建了一個(gè)線程池threadPoolExecutor贿条,并設(shè)置了核心線程會(huì)超時(shí)關(guān)閉,最后并把這個(gè)線程池指向THREAD_POOL_EXECUTOR增热。

(九)闪唆、私有的靜態(tài)類SerialExecutor

代碼在AsyncTask.java 226行

    private static class SerialExecutor implements Executor {
        // 循環(huán)數(shù)組實(shí)現(xiàn)的雙向Queue,大小是2的倍數(shù)钓葫,默認(rèn)是16悄蕾,有隊(duì)頭和隊(duì)尾巴兩個(gè)下標(biāo)
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        // 正在運(yùn)行runnable
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            // 添加到雙向隊(duì)列中去
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                         //執(zhí)行run方法
                        r.run();
                    } finally {
                        //無論執(zhí)行結(jié)果如何都會(huì)取出下一個(gè)任務(wù)執(zhí)行
                        scheduleNext();
                    }
                }
            });
           // 如果沒有活動(dòng)的runnable,則從雙端隊(duì)列里面取出一個(gè)runnable放到線程池中運(yùn)行
           // 第一個(gè)請(qǐng)求任務(wù)過來的時(shí)候mActive是空的
            if (mActive == null) {
                 //取出下一個(gè)任務(wù)來
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            //從雙端隊(duì)列中取出一個(gè)任務(wù)
            if ((mActive = mTasks.poll()) != null) {
                //線線程池執(zhí)行取出來的任務(wù)础浮,真正的執(zhí)行任務(wù)
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
  • 首先帆调,注意SerialExecutor的execute是synchronized的,所以無論多個(gè)少任務(wù)調(diào)用execute()都是同步的豆同。
  • 其次番刊,SerialExecutor里面一個(gè)ArrayDeque隊(duì)列,通過代碼我們知道影锈,SerialExecutor是通過ArrayDeque來管理Runnable對(duì)象的芹务。通過上面我們知道execute()是同步的蝉绷,所以如果你有10個(gè)任務(wù)同時(shí)調(diào)用SerialExecutor的execute()方法,就會(huì)把10個(gè)Runnable先后放入到mTasks中去枣抱,可見mTasks緩存了將要執(zhí)行的Runnable熔吗。
  • 再次1,如果我們第一個(gè)執(zhí)行execute()方法時(shí)佳晶,會(huì)調(diào)用ArrayDeque的offer()方法將傳入的Runnable對(duì)象添加到隊(duì)列的尾部桅狠,然后判斷mActive是不是null,因?yàn)槭堑谝淮握{(diào)用轿秧,此時(shí)mActive還沒有賦值中跌,所以mActive等于null。所以此時(shí)mActive == null成立菇篡,所以會(huì)調(diào)用scheduleNext()方法漩符。
  • 再次2,我們?cè)谡{(diào)用scheduleNext()里面驱还,看到會(huì)調(diào)用mTasks.poll()嗜暴,我們知道這是從隊(duì)列中取出頭部元素,然后把這個(gè)頭部元素賦值給mActive铝侵,然后讓THREAD_POOL_EXECUTOR這個(gè)線程池去執(zhí)行這個(gè)mActive的Runnable對(duì)象灼伤。
  • 再次3触徐,如果這時(shí)候有第二個(gè)任務(wù)入隊(duì)咪鲜,但是此時(shí)mActive!=null,不會(huì)執(zhí)行scheduleNext()撞鹉,所以如果第一個(gè)任務(wù)比較耗時(shí)疟丙,后面的任務(wù)都會(huì)進(jìn)入隊(duì)列等待。
  • 再次4鸟雏,上面知道由于第二個(gè)任務(wù)入隊(duì)后享郊,由于mActive!=null,所以不會(huì)執(zhí)行scheduleNext()孝鹊,那樣這樣后面的任務(wù)豈不是永遠(yuǎn)得不到處理炊琉,當(dāng)然不是,因?yàn)樵趏ffer()方法里面?zhèn)魅胍粋€(gè)Runnable的匿名類又活,并且在此使用了finnally代碼苔咪,意味著無論發(fā)生什么情況,這個(gè)finnally里面的代碼一定會(huì)執(zhí)行柳骄,而finnally代碼塊里面就是調(diào)用了scheduleNext()方法团赏,所以說每當(dāng)一個(gè)任務(wù)執(zhí)行完畢后,下一個(gè)任務(wù)才會(huì)執(zhí)行耐薯。
  • 最后舔清,SerialExecutor其實(shí)模仿的是單一線程池的效果丝里,如果我們快速地啟動(dòng)了很多任務(wù),同一時(shí)刻只會(huì)有一個(gè)線程正在執(zhí)行体谒,其余的均處于等待狀態(tài)杯聚。

PS:scheduleNext()方法是synchronized,所以也是同步的

重點(diǎn)補(bǔ)充:

在Android 3.0 之前是并沒有SerialExecutor這個(gè)類的营密,那個(gè)時(shí)候是直接在AsyncTask中構(gòu)建一個(gè)sExecutor常量械媒,并對(duì)線程池總大小,同一時(shí)刻能夠運(yùn)行的線程數(shù)做了規(guī)定评汰,代碼如下:

private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,  
        MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory); 

四纷捞、AsyncTask類的構(gòu)造函數(shù)

代碼如下:

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {

                // 設(shè)置方法已經(jīng)被調(diào)用
                mTaskInvoked.set(true);
                 // 設(shè)定結(jié)果變量
                Result result = null;
                try {
                    //設(shè)置線程優(yōu)先級(jí)
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    //執(zhí)行任務(wù)
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    // 產(chǎn)生異常則設(shè)置失敗
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    // 無論執(zhí)行成功還是出現(xiàn)異常,最后都會(huì)調(diào)用PostResult
                    postResult(result);
                }
                return result;
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    // 就算沒有調(diào)用讓然去設(shè)置結(jié)果
                    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);
                }
            }
        };
    }

通過注釋我們知道被去,這個(gè)方法創(chuàng)建一個(gè)異步任務(wù)主儡,構(gòu)造函數(shù)必須在UI線程調(diào)用

這里面設(shè)計(jì)了兩個(gè)概念Callable和FutureTask蕴轨,如果大家對(duì)這兩個(gè)類有疑問云头,可以看我上一篇文章Android Handler機(jī)制12之Callable喂柒、Future和FutureTask

構(gòu)造函數(shù)也比較簡(jiǎn)單岗屏,主要就是給mWorker和mFuture初始化菠净,其中WorkerRunnable實(shí)現(xiàn)了Callable接口封恰,

在構(gòu)造函數(shù)里面調(diào)用了postResult(Result)和postResultIfNotInvoked(Result)西采,那我們就來分別看下

1美尸、postResult(Result)方法
     // doInBackground執(zhí)行完畢捣染,發(fā)送消息
    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        // 獲取一個(gè)Message對(duì)象
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        // 發(fā)送給線程
        message.sendToTarget();
        return result;
    }

通過代碼我們知道

  • 生成一個(gè)Message
  • 把這個(gè)Message發(fā)送出

這里面調(diào)用了 getHandler()骄瓣,那我們來看下這個(gè)方法是怎么寫的

2、getHandler()方法
    private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }

我們看到返回的是InternalHandler對(duì)象耍攘,上面說過了InternalHandler其實(shí)是關(guān)聯(lián)主線程的榕栏,所以上面方法 message.sendToTarget(); 其實(shí)是把消息發(fā)送給主線程。

大家注意一下 這里的Message的what值為MESSAGE_POST_RESULT蕾各,我們來看下InternalHandler遇到InternalHandler這種消息是怎么處理的

    private static class InternalHandler extends Handler {
        ... 
        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;
               ...
            }
        }
    }

我們看到MESSAGE_POST_RESULT對(duì)應(yīng)的是指是執(zhí)行AsyncTask的finish(Result)方法扒磁,所以我們可以這樣說,無論AsyncTask是成功了還是失敗了式曲,最后都會(huì)執(zhí)行finish(Result)方法妨托。那我們來看下finish(Result)方法里面都干了什么?

2.1吝羞、finish(Result result) 方法
    private void finish(Result result) {
        if (isCancelled()) {
            // 如果消息取消了兰伤,執(zhí)行onCancelled方法
            onCancelled(result);
        } else {
            // 如果消息沒有取消,則執(zhí)行onPostExecute方法
            onPostExecute(result);
        }
        // 設(shè)置狀態(tài)值
        mStatus = Status.FINISHED;
    }

注釋寫的很清楚了脆贵,我這里就不說明了医清,通過上面的代碼和finish方法的分析,我們知道無論成功還是失敗卖氨,最后一定會(huì)調(diào)用finish(Result)方法会烙,所以最后狀態(tài)的值為FINISHED负懦。

3、postResultIfNotInvoked(Result)方法
    private void postResultIfNotInvoked(Result result) {
        // 獲取mTaskInvoked的值
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

通過上面代碼我們知道柏腻,如果mTaskInvoked不為true纸厉,則執(zhí)行postResult,但是在mWorker初始化的時(shí)候?yàn)閠rue五嫂,除非在沒有執(zhí)行call方法時(shí)候颗品,如果沒有執(zhí)行call,說明這個(gè)異步線程還沒有開始執(zhí)行沃缘,這個(gè)時(shí)候mTaskInvoked為false躯枢。而這時(shí)候調(diào)用postResultIfNotInvoked則還是會(huì)執(zhí)行postResult(Result),這樣保證了AsyncTask一定有返回值槐臀。

五锄蹂、AsyncTask類核心方法解析

(一)、void onPreExecute()

    /**
     * Runs on the UI thread before {@link #doInBackground}.
     *
     * @see #onPostExecute
     * @see #doInBackground
     */
     // 在調(diào)用doInBackground()方法之前水慨,跑在主線程上
    @MainThread
    protected void onPreExecute() {
    }

其實(shí)注釋很清楚了得糜,在task任務(wù)開始執(zhí)行的時(shí)候在主線程調(diào)用,在doInBackground(Params… params) 方法之前調(diào)用晰洒。

(二)朝抖、AsyncTask<Params, Progress, Result> onPreExecute() 方法

    /**
     * Executes the task with the specified parameters. The task returns
     * itself (this) so that the caller can keep a reference to it.
     * 
     * <p>Note: this function schedules the task on a queue for a single background
     * thread or pool of threads depending on the platform version.  When first
     * introduced, AsyncTasks were executed serially on a single background thread.
     * Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
     * to a pool of threads allowing multiple tasks to operate in parallel. Starting
     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
     * executed on a single thread to avoid common application errors caused
     * by parallel execution.  If you truly want parallel execution, you can use
     * the {@link #executeOnExecutor} version of this method
     * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
     * on its use.
     *
     * <p>This method must be invoked on the UI thread.
     *
     * @param params The parameters of the task.
     *
     * @return This instance of AsyncTask.
     *
     * @throws IllegalStateException If {@link #getStatus()} returns either
     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
     *
     * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
     * @see #execute(Runnable)
     */
    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

首先來翻譯一下注釋

  • 使用指定的參數(shù)來執(zhí)行任務(wù),這個(gè)方法的返回值是this谍珊,也就是它自己治宣,因?yàn)檫@樣設(shè)計(jì)的目的是可以保持對(duì)它的引用。
  • 注意:它的調(diào)度模式是不同的抬驴,一種是單個(gè)后臺(tái)線程炼七,一種是通過線程池來實(shí)現(xiàn)缆巧,具體那種模式是根據(jù)android版本的不同而不同布持,當(dāng)最開始引入AsyncTask的時(shí)候,AsyncTask是單個(gè)后臺(tái)線程上串行執(zhí)行陕悬,從Android DONUT 開始题暖,模式變更為通過線程池多任務(wù)并行執(zhí)行。在Android HONEYCOMB開始捉超,又變回了在單個(gè)線程上執(zhí)行胧卤,這樣可以避免并行執(zhí)行的錯(cuò)誤。如果你還是想并行執(zhí)行拼岳,你可以使用executeOnExecutor()方法并且第一個(gè)參數(shù)是THREAD_POOL_EXECUTOR就可以了枝誊,不過,請(qǐng)注意有關(guān)使用警告惜纸。
  • 必須在UI主線程上調(diào)用此方法叶撒。

通過代碼我們看到绝骚,它的內(nèi)部其實(shí)是調(diào)用executeOnExecutor(Executor exec, Params... params)方法,只不過第一個(gè)參數(shù)傳入的是sDefaultExecutor祠够,而sDefaultExecutor是SerialExecutor的對(duì)象压汪。上面我們提到了SerialExecutor里面利用ArrayDeque來實(shí)現(xiàn)串行的,所以我們可以推測(cè)出如果在executeOnExecutor(Executor exec, Params... params)方法里面如果第一個(gè)參數(shù)是自定義的Executor古瓤,AsyncTask就可以實(shí)現(xiàn)并發(fā)執(zhí)行止剖。

(三)、executeOnExecutor(Executor exec, Params... params) 方法

    /**
     * Executes the task with the specified parameters. The task returns
     * itself (this) so that the caller can keep a reference to it.
     * 
     * <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
     * allow multiple tasks to run in parallel on a pool of threads managed by
     * AsyncTask, however you can also use your own {@link Executor} for custom
     * behavior.
     * 
     * <p><em>Warning:</em> Allowing multiple tasks to run in parallel from
     * a thread pool is generally <em>not</em> what one wants, because the order
     * of their operation is not defined.  For example, if these tasks are used
     * to modify any state in common (such as writing a file due to a button click),
     * there are no guarantees on the order of the modifications.
     * Without careful work it is possible in rare cases for the newer version
     * of the data to be over-written by an older one, leading to obscure data
     * loss and stability issues.  Such changes are best
     * executed in serial; to guarantee such work is serialized regardless of
     * platform version you can use this function with {@link #SERIAL_EXECUTOR}.
     *
     * <p>This method must be invoked on the UI thread.
     *
     * @param exec The executor to use.  {@link #THREAD_POOL_EXECUTOR} is available as a
     *              convenient process-wide thread pool for tasks that are loosely coupled.
     * @param params The parameters of the task.
     *
     * @return This instance of AsyncTask.
     *
     * @throws IllegalStateException If {@link #getStatus()} returns either
     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
     *
     * @see #execute(Object[])
     */
    @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)");
            }
        }
        //設(shè)置狀態(tài)
        mStatus = Status.RUNNING;
        從這里我們看出onPreExecute是先執(zhí)行落君,并且在UI線程
        onPreExecute();
        // 設(shè)置參數(shù)
        mWorker.mParams = params;
        // 開啟了后臺(tái)線程去計(jì)算穿香,這是真正調(diào)用doInBackground的地方
        exec.execute(mFuture);
        // 接著會(huì)有onProgressUpdate會(huì)被調(diào)用,最后是onPostExecute
        return this;
    }

老規(guī)矩 先翻譯一下注釋:

  • 使用指定的參數(shù)來執(zhí)行任務(wù)绎速,這個(gè)方法的返回值是this扔水,也就是它自己,因?yàn)檫@樣設(shè)計(jì)的目的是可以保持對(duì)它的引用朝氓。
  • 這個(gè)方法通常與THREAD_POOL_EXECUTOR一起使用魔市,這樣可以讓多個(gè)人物在AsyncTask管理的線程池上并行運(yùn)行,但你也可以使用自定義的Executor赵哲。
  • 警告:由于大多數(shù)情況并沒有定義任務(wù)的操作順序待德,所以在線程池中多任務(wù)并行并不常見。例如:如果修改共同狀態(tài)的任務(wù)(就像點(diǎn)擊按鈕就可以編寫文件)枫夺,對(duì)修改的順訊沒有保證将宪。在很少的情況下,如果沒有仔細(xì)工作橡庞,較新版本的數(shù)據(jù)可能會(huì)被較舊的數(shù)據(jù)覆蓋较坛,從而導(dǎo)致數(shù)據(jù)丟失和穩(wěn)定性問題。而這些變更最好是連續(xù)執(zhí)行扒最,因?yàn)檫@樣可以保證工作的有序化丑勤,無論平臺(tái)版本如何,你可以使用SERIAL_EXECUTOR吧趣。
  • 必須在UI主線程上調(diào)用此方法法竞。
  • 參數(shù)exec:為了實(shí)現(xiàn)輕松解耦,我們可以使用THREAD_POOL_EXECUTOR這個(gè)線程池可以作為合適的進(jìn)程范圍的線程池
  • 參數(shù)params:任務(wù)的參數(shù)

那我們來看下一下代碼强挫,代碼里面的邏輯如下:

  • 該方法首先是判斷mStatus狀態(tài)岔霸,如果是正在運(yùn)行(RUNNING)或者已經(jīng)結(jié)束(FINISHED),就會(huì)拋出異常俯渤。
  • 接著設(shè)置狀態(tài)為RUNNING呆细,即運(yùn)行,執(zhí)行onPreExecute()方法八匠,并把參數(shù)的值賦給mWorker.mParams
  • 于是Executor去執(zhí)行execute的方法絮爷,學(xué)過Java多線程的都知道诡曙,這里方法是開啟一個(gè)線程去執(zhí)行mFuture的run()方法(由于mFuture用Callable構(gòu)造,所以其實(shí)是執(zhí)行的Callable的call()方法略水,而mWorker是Callable的是實(shí)現(xiàn)類价卤,所以最終執(zhí)行的是mWorker的call()方法)

PS:mFuture和mWorker都是在AsyncTask的構(gòu)造方法中初始化過的。

(四)渊涝、 publishProgress(Progress... values) 方法

主要是設(shè)置后臺(tái)進(jìn)度慎璧,onProgressUpdate會(huì)被調(diào)用

    /**
     * This method can be invoked from {@link #doInBackground} to
     * publish updates on the UI thread while the background computation is
     * still running. Each call to this method will trigger the execution of
     * {@link #onProgressUpdate} on the UI thread.
     *
     * {@link #onProgressUpdate} will not be called if the task has been
     * canceled.
     *
     * @param values The progress values to update the UI with.
     *
     * @see #onProgressUpdate
     * @see #doInBackground
     */
    @WorkerThread
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

這個(gè)方法內(nèi)部實(shí)現(xiàn)很簡(jiǎn)單

  • 首先判斷 任務(wù)是否已經(jīng)被取消,如果已經(jīng)被取消了跨释,則什么也不做
  • 如果任務(wù)沒有被取消胸私,則通過InternalHandler發(fā)送一個(gè)what為MESSAGE_POST_PROGRESS的Message

這樣就進(jìn)入了InternalHandler的handleMessage(Message)里面了,而我們知道InternalHandler的Looper是Looper.getMainLooper()鳖谈,所以處理Message是在主線程中岁疼,我們來看下代碼

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

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

通過代碼,我們看到如果what為MESSAGE_POST_PROGRESS缆娃,則會(huì)在主線程中調(diào)用onProgressUpdate(result.mData)捷绒,這也就是為什么我們平時(shí)在異步線程調(diào)用publishProgress(Progress...)方法后,可以在主線程中的onProgressUpdate(rogress... values)接受數(shù)據(jù)了贯要。

六暖侨、AsyncTask核心流程

其實(shí)在上面講解過程中,我基本上已經(jīng)把整體流程講解過了崇渗,我這里補(bǔ)上一張圖字逗,比較全面的闡述了AsyncTask的執(zhí)行流程如下:

asynctask執(zhí)行流程.png

對(duì)應(yīng)的時(shí)序圖如下:

時(shí)序圖.png

大家如果手機(jī)上看不清,我建議down下來在電腦上看宅广。

如果結(jié)合AsyncTask的狀態(tài)值葫掉,流程圖如下:

流程.png

如果把AsyncTask和Handler分開則流程圖如下:

AsyncTask和Handler分開.png

最后如果把AsyncTask里面所有類的涉及關(guān)系整理如下圖:

20140513095959437.jpeg

七、AsyncTask與Handler

  • AsyncTask:
    • 優(yōu)點(diǎn):AsyncTask是一個(gè)輕量級(jí)的異步任務(wù)處理類跟狱,輕量級(jí)體現(xiàn)在俭厚,使用方便,代碼簡(jiǎn)潔兽肤,而且整個(gè)異步任務(wù)的過程可以通過cancel()進(jìn)行控制
    • 缺點(diǎn):不適用處理長(zhǎng)時(shí)間的異步任務(wù)套腹,一般這個(gè)異步任務(wù)的過程最好控制在幾秒以內(nèi)绪抛,如果是長(zhǎng)時(shí)間的異步任務(wù)就需要考慮多線程的控制問題资铡;當(dāng)處理多個(gè)異步任務(wù)時(shí),UI更新變得困難幢码。
  • Handler:
    • 優(yōu)點(diǎn):代碼結(jié)構(gòu)清晰笤休,容易處理多個(gè)異步任務(wù)
    • 缺點(diǎn):當(dāng)有多個(gè)異步任務(wù)時(shí),由于要配合Thread或Runnable症副,代碼可能會(huì)稍顯冗余店雅。

總之政基,AsyncTask不失為一個(gè)非常好用的異步任務(wù)處理類。不過我從事Android開發(fā)5年多了闹啦,很少會(huì)用到AsyncTask沮明,一般異步任務(wù)都是Handler。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末窍奋,一起剝皮案震驚了整個(gè)濱河市荐健,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌琳袄,老刑警劉巖江场,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異窖逗,居然都是意外死亡址否,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門碎紊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來佑附,“玉大人,你說我怎么就攤上這事仗考“镓遥” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵痴鳄,是天一觀的道長(zhǎng)瘟斜。 經(jīng)常有香客問我,道長(zhǎng)痪寻,這世上最難降的妖魔是什么螺句? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮橡类,結(jié)果婚禮上蛇尚,老公的妹妹穿的比我還像新娘。我一直安慰自己顾画,他們只是感情好取劫,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著研侣,像睡著了一般谱邪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上庶诡,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天惦银,我揣著相機(jī)與錄音,去河邊找鬼。 笑死扯俱,一個(gè)胖子當(dāng)著我的面吹牛书蚪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播迅栅,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼殊校,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了读存?” 一聲冷哼從身側(cè)響起箩艺,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宪萄,沒想到半個(gè)月后艺谆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拜英,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年静汤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片居凶。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡虫给,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出侠碧,到底是詐尸還是另有隱情抹估,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布弄兜,位于F島的核電站药蜻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏替饿。R本人自食惡果不足惜语泽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望视卢。 院中可真熱鬧踱卵,春花似錦、人聲如沸据过。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绳锅。三九已至西饵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間榨呆,已是汗流浹背罗标。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工庸队, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留积蜻,地道東北人闯割。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像竿拆,于是被迫代替她去往敵國(guó)和親宙拉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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

  • 由于從wordpress將文章倒回,發(fā)現(xiàn)格式有點(diǎn)混亂,經(jīng)努力調(diào)整后依然有部分的格式還未調(diào)教好,請(qǐng)多多包涵. 分析A...
    walker_lee0707閱讀 1,185評(píng)論 3 51
  • AsyncTask的相關(guān)結(jié)論 下面是AsyncTask的相關(guān)結(jié)論丙笋,相關(guān)結(jié)論都會(huì)在下面的源碼分析中一一印證谢澈。 onP...
    未見哥哥閱讀 261評(píng)論 0 2
  • Android開發(fā)者:你真的會(huì)用AsyncTask嗎? 導(dǎo)讀.1 在Android應(yīng)用開發(fā)中御板,我們需要時(shí)刻注意保證...
    cxm11閱讀 2,701評(píng)論 0 29
  • AsyncTask異步任務(wù)锥忿,用于執(zhí)行耗時(shí)任務(wù)并在UI線程中更新結(jié)果。 我們都知道怠肋,Android UI線程中不能執(zhí)...
    iyifei閱讀 3,459評(píng)論 2 9
  • 01 第一次打開簡(jiǎn)書,是為了向朋友們推薦天禪映畫杈抢,沒想它卻成了我的另一個(gè)興趣愛好数尿,或者更準(zhǔn)確的說,它開啟了另一種表...
    映靈77閱讀 357評(píng)論 0 2