Android源碼之路(二、AsyncTask)

參考

https://www.baidu.com/link?url=QNRznJEBT25k0bpgVD3bOniOia2W85eiPIWrS93YFknyrHoFDGrJVtoax2ZYpiiErtRW7VD-sNEgCRNespIhSK&wd=&eqid=9a27957100030dcd000000065aac77c0

http://www.reibang.com/p/79cc3c5fc9a3

http://blog.csdn.net/majihua817/article/details/51658465

以下用法和源碼分析基于android-27(即版本android 8.1.0)

要點總結(jié):

1.進(jìn)程所有AsyncTask默認(rèn)并不是并行執(zhí)行的飞盆,通常默認(rèn)的 使用execute執(zhí)行 的AsyncTask是排隊按順序執(zhí)行的,同一時間內(nèi)只有一個AsyncTask會運行;

2.進(jìn)程中使用executeOnExecutor(Executor exec,Params...params)根據(jù)傳入的線程池效果,可以實現(xiàn)同一時間多個AsyncTask異步執(zhí)行的效果;

3.常用的回調(diào)方法有:onPreExecute()、doInBackground(Params... params)种远、onProgressUpdate(Progress... values)、onPostExecute(Result result)

  • a. 執(zhí)行順序為onPreExecute -> doInBackground--> (onProgressUpdate)->onPostExecute

  • b. onPreExecute: 運行在ui線程顽耳,當(dāng)代碼執(zhí)行AsyncTask.execute(Params...params)后會被調(diào)用坠敷,一般可用于界面上一些初始化操作,比如彈出下載對話框等;

  • c. doInBackground:運行在后臺非ui線程射富,用來處理耗時的任務(wù)膝迎,如下載、數(shù)據(jù)處理等胰耗;

  • d. onProgressUpdate:運行在ui線程限次,可用來處理界面上的一些進(jìn)度更新相關(guān)操作;在doInBackground中調(diào)用publishProgress后柴灯,可觸發(fā)onProgressUpdate卖漫;

  • e. 當(dāng)然onPreExecute也可以使用publishProgress觸發(fā)onProgressUpdate,只是二者都是ui線程费尽,所以并沒有實際意義;

  • f. 注意的是publishProgress也是使用的handler發(fā)送消息來觸發(fā)的onProgressUpdate,所以注意的是
    doInBackground沒人為干預(yù)的話并不會因此堵塞等待onProgressUpdate執(zhí)行完畢

  • g. onPostExecute:運行在ui線程,可用于界面提示操作完成懊亡,在doInBackground執(zhí)行完使用return后調(diào)用依啰;

  • h.源碼中對這些重要回調(diào)方法都有對應(yīng)的@MainThread乎串、@WorkerThread線程注解店枣,但這個注解目前主要用于IDE編譯檢查錯誤用的,實際上execute等依舊可以在子線程中調(diào)用叹誉,當(dāng)然onPreExecute此時就不能處理ui界面鸯两,否則會拋出異常;但建議調(diào)用的地方和注解一致

4.執(zhí)行過一個次或者正在執(zhí)行的AsyncTask不能再次通過execute或者executeOnExecutor進(jìn)行重復(fù)執(zhí)行

5.使用executeOnExecutor并行執(zhí)行的話,根據(jù)傳入的線程池的設(shè)置會有隊列大小的限制长豁,通常直接使用AsyncTask中AsyncTask.THREAD_POOL_EXECUTOR這個線程池的話:

//cpu核數(shù),假設(shè)4
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); 
//核心線程數(shù),3
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//最大同時執(zhí)行的線程數(shù)9   
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//空閑線程超過30秒被回收
private static final int KEEP_ALIVE_SECONDS = 30;               
//等待隊列允許的最大數(shù)量為128
private static final BlockingQueue<Runnable> sPoolWorkQueue =new LinkedBlockingQueue<Runnable>(128);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
        CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
        sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;

(假設(shè)終端cpu數(shù)目為4)因為該線程池運行同時運行的最大線程數(shù)為9,等待隊列最大為128钧唐,如果每一個asynctask的doInBackground中耗時非常久,一次性添加超過9+128=137個task的話(比如listview中一次性創(chuàng)建),那么將會引起異常java.util.concurrent.RejectedExecutionException

6.使用execute的話匠襟,因為有隊列緩存(沒大小限制钝侠,除非內(nèi)存爆掉),串行執(zhí)行酸舍,所以不存在線程池中任務(wù)超出大小的情況

7.AsyncTaskd的cancel方法只是簡單把標(biāo)志位改為true帅韧,最后使用Thread.interrupt去中斷線程執(zhí)行,但是這并不保證會馬上停止執(zhí)行啃勉,所以可以在doInBackground中使用isCancelled來判斷任務(wù)是否被取消

要點解釋

(來自參考資料http://www.reibang.com/p/79cc3c5fc9a3)

在Android 1.5剛引入的時候忽舟,AsyncTask的execute是串行執(zhí)行的;到了Android 1.6直到Android 2.3.2淮阐,又被修改為并行執(zhí)行了叮阅,這個執(zhí)行任務(wù)的線程池就是THREAD_POOL_EXECUTOR,因此在一個進(jìn)程內(nèi)泣特,所有的AsyncTask都是并行執(zhí)行的浩姥;但是在Android 3.0以后,如果你使用execute函數(shù)直接執(zhí)行AsyncTask状您,那么這些任務(wù)是串行執(zhí)行的及刻。因此結(jié)論就來了:Android 3.0以上,AsyncTask默認(rèn)并不是并行執(zhí)行的竞阐。

由于同一個進(jìn)程的AsyncTask都是在一個線程池中缴饭,如果默認(rèn)是并行的,那么多個線程同時執(zhí)行多個task中的doInBackground操作骆莹,而doInBackground又訪問修改相同的資源颗搂,這邊往往會忽略對資源的同步處理問題特幔,經(jīng)常會導(dǎo)致不可預(yù)料的錯誤結(jié)果隐轩,為此默認(rèn)情況下使用execute執(zhí)行的AsyncTask默認(rèn)為串行執(zhí)行;

如果處理好資源同步問題,可以使用executeOnExecutor傳入合適的線程池及志,來達(dá)到AsyncTask并行執(zhí)行的效果;

優(yōu)缺點總結(jié)

優(yōu)點:

  • 1.封裝后實現(xiàn)簡單的的子線程和ui線程間的一個切換,省去了用戶需要子線程更新ui界面繁瑣的操作

缺點(參考http://blog.csdn.net/goodlixueyong/article/details/45895997):

  • 1.需要注意串行還是并行執(zhí)行运褪,在1.5是串行宾袜,1.6-2.3.2是并行,3.0之后默認(rèn)使用execute時串行貌嫡,如果使用executeOnExecutor則是并行比驻;

  • 2.所謂的串行,實際上主要是針對doInBackground方法里面的操作而言的岛抄,串行時并不會等到task中onPostExecute執(zhí)行完才觸發(fā)下一份asynctask,只要doInBackground執(zhí)行完成就會促發(fā)下一個asynctask

  • 3.可能導(dǎo)致內(nèi)存泄露或者ui更新異常問題别惦,如果是activity中非靜態(tài)內(nèi)部asynctask子類,默認(rèn)隱式持有一個activity的引用夫椭,在activity銷毀之前掸掸,注意要停止asynctask;不然后臺線程一直運行蹭秋,導(dǎo)致了內(nèi)存泄露扰付,還可能在要更新ui時,該view已經(jīng)不存在而導(dǎo)致異常仁讨;

  • 4.如果activity因為轉(zhuǎn)屏重建或者被后臺異常終結(jié)羽莺,之前運行的asynctask還會持有一個之前activity的引用,更新這個無效的引用上的view需要注意對view有效性的判斷

  • 5.并行執(zhí)行的時候陪竿,需要考慮下線程池能夠處理的任務(wù)大小

使用方法

聲明MyAsyncTask繼承并實現(xiàn)AsyncTask相關(guān)回調(diào):

    public class MyAsyncTask extends AsyncTask<String, Integer, Boolean>{
        String TAG="MyAsyncTask";
        public MyAsyncTask(String tag) {
            super();
            this.TAG=tag;
        }
        //doInBackground開始之前調(diào)用,ui線程,可用于界面上的一些初始化操作禽翼,比如彈出下載對話框
        @Override
        protected void onPreExecute() {
            Log.d(TAG,"onPreExecute "+Thread.currentThread());
            Toast.makeText(context,"onPreExecute",Toast.LENGTH_SHORT).show();
        }
        //用于執(zhí)行后臺任務(wù),非ui線程族跛,用于處理耗時任務(wù)闰挡,下載,數(shù)據(jù)處理等
        @Override
        protected Boolean doInBackground(String... params) {
            Log.d(TAG,"doInBackground "+Thread.currentThread());
            int count = params.length;
            for(int i=0;i<count;i++){
            //判斷任務(wù)是否取消礁哄,取消則停止,用戶調(diào)用AsyncTask.cancel()后設(shè)置該標(biāo)志位
            //調(diào)用AsyncTask.cancel()并不能直接停止一個asynctask,
           // 需要在doInBackground/onProgressUpdate/onPreExecute手動判斷該標(biāo)志位
                if(isCancelled()){
                    return false
                }
                String p = params[i];
                Log.d(TAG,"doInBackground:"+p);
                publishProgress(i);
            }
            return true;
        }

        //當(dāng)后臺任務(wù)doInBackground調(diào)用了publishProgress(Progress...)方法后长酗,這個方法會被調(diào)用
        //用于執(zhí)行處理過程中的進(jìn)度更新之類,ui線程,可用于更新下載對話框的進(jìn)度條
        @Override
        protected void onProgressUpdate(Integer... values) {
            Log.d(TAG,"onProgressUpdate:"+values[0]+"  "+Thread.currentThread());
            Toast.makeText(context,"onProgressUpdate:"+values[0],Toast.LENGTH_SHORT).show();
        }

        //當(dāng)后臺任務(wù)doInBackground執(zhí)行完畢并通過return語句進(jìn)行返回時桐绒,這個方法就會被調(diào)用
        //ui線程夺脾,可用于界面更新處理完成
        @Override
        protected void onPostExecute(Boolean aBoolean) {
            Log.d(TAG,"onPostExecute:"+aBoolean+"  "+Thread.currentThread());
            Toast.makeText(context,"onPostExecute",Toast.LENGTH_SHORT).show();
        }


        //AsyncTaskd的cancel方法只是簡單把標(biāo)志位改為true,最后使用Thread.interrupt去中斷線程執(zhí)行茉继,但是這并不保證會馬上停止執(zhí)行咧叭,所以可以在doInBackground中使用isCancelled來判斷任務(wù)是否被取消
        //ui線程,可用于取消后關(guān)閉ui界面提示等
        @Override
        protected void onCancelled(Boolean aBoolean) {
            Log.d(TAG,"onCancelled:"+aBoolean+"  "+Thread.currentThread());
        }

    }

創(chuàng)建相關(guān)實例并執(zhí)行AsyncTask:

測試一:普通使用

    Log.d(TAG,"btn1 start");
     MyAsyncTask myAsyncTask =new MyAsyncTask("task1"); //創(chuàng)建AsyncTask子類實例
     myAsyncTask.execute("參數(shù)1","參數(shù)2");      //開始執(zhí)行
     Log.d(TAG,"btn1 end");
    
    **日志輸出**:
    btn1 start                              
    onPreExecute Thread[main,5,main]      //可以看見調(diào)用execute后烁竭,onPreExecute立馬執(zhí)行
    btn1 end
    doInBackground Thread[AsyncTask #1,5,main]   
    doInBackground:參數(shù)1
    doInBackground:參數(shù)2
    //doInBackground調(diào)用publishProgress后,由handler觸發(fā)onProgressUpdate菲茬,與doInBackground為2個線程異步執(zhí)行
    onProgressUpdate:0  Thread[main,5,main]  
    onProgressUpdate:1  Thread[main,5,main]
    onPostExecute:true  Thread[main,5,main] //全部操作完成后調(diào)用

測試二:多個asyncTask使用驗證串行執(zhí)行

    Log.d(TAG,"btn1 start");
    MyAsyncTask myAsyncTask =new MyAsyncTask("task1");
    MyAsyncTask myAsyncTask2 =new MyAsyncTask("task2");
    myAsyncTask.execute("參數(shù)1","參數(shù)2");
    myAsyncTask2.execute("參數(shù)1","參數(shù)2");
    Log.d(TAG,"btn1 end");
                    
    日志輸出:
    btn1 start
    //可以看見各自調(diào)用execute后,task1,task2的onPreExecute立馬執(zhí)行,互不影響
    task1: onPreExecute Thread[main,5,main] 
    task2: onPreExecute Thread[main,5,main]
    btn1 end
    task1: doInBackground Thread[AsyncTask #1,5,main] //doInBackground是按序執(zhí)行的
    task1: doInBackground:參數(shù)1
    task1: doInBackground:參數(shù)2
    task2: doInBackground Thread[AsyncTask #2,5,main]
    task2: doInBackground:參數(shù)1
    task2: doInBackground:參數(shù)2
    //onProgressUpdate和onProgressUpdate也是按序執(zhí)行的
    //這邊看到可能存在后續(xù)asyncTask執(zhí)行doInBackground過程中婉弹,
    前面的task才剛觸發(fā)onProgressUpdate和onPostExecute
    task1: onProgressUpdate:0  Thread[main,5,main]   
    task1: onProgressUpdate:1  Thread[main,5,main]  
    task1: onPostExecute:true  Thread[main,5,main]
    task2: onProgressUpdate:0  Thread[main,5,main]
    task2: onProgressUpdate:1  Thread[main,5,main]
    task2: onPostExecute:true  Thread[main,5,main]

測試三:并行執(zhí)行:

MyAsyncTask myAsyncTask =new MyAsyncTask("task1");
    MyAsyncTask myAsyncTask2 =new MyAsyncTask("task2");
    myAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"參數(shù)1","參數(shù)2");
    myAsyncTask2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"參數(shù)1","參數(shù)2");
    日志輸出(doInBackground 添加Thread.sleep方便模擬):
    btn1 start
    task1: onPreExecute Thread[main,5,main]
    task2: onPreExecute Thread[main,5,main]
    //task1與task2的doInBackground部分交替執(zhí)行
    task1: doInBackground Thread[AsyncTask #1,5,main]
    task1: doInBackground:參數(shù)1                             
    task2: doInBackground Thread[AsyncTask #2,5,main]
    task2: doInBackground:參數(shù)1                             
    btn1 end
    task1: onProgressUpdate:0  Thread[main,5,main]
    task2: onProgressUpdate:0  Thread[main,5,main]
    task1: doInBackground:參數(shù)2
    task2: doInBackground:參數(shù)2
    task1: onProgressUpdate:1  Thread[main,5,main]
    task2: onProgressUpdate:1  Thread[main,5,main]
    task1: onPostExecute:true  Thread[main,5,main]
    task2: onPostExecute:true  Thread[main,5,main]

從測試中可以看出onPreExecute在各自AsyncTask調(diào)用execute后立即執(zhí)行睬魂,后續(xù)源碼分析可知道onPreExecute不由handler觸發(fā),否則可能與doInBackground執(zhí)行時序有差別;

測試二中:
后續(xù)從源碼分析可以知道使用execute觸發(fā)的AsyncTask中的doInBackground部分實際上是在線程池中排隊執(zhí)行的镀赌,所以只有一個任務(wù)的doInBackground執(zhí)行完氯哮,才會獲取下一個任務(wù)的doInBackground進(jìn)行執(zhí)行;

從源碼分析可以知道onProgressUpdate商佛、onPostExecute是通過handler消息控制的喉钢,本身也是按序執(zhí)行的;多個AsyncTask的不同的生命周期步驟其實會有穿插威彰;

從日志輸出和源碼原理可知,AsyncTask的按序執(zhí)行相對來講有一定的不足出牧,不會等待一個AsyncTask完整執(zhí)行完后onPreExecute -> doInBackground--> (onProgressUpdate)->onPostExecute,后下一個AsyncTask才允許開始它的生命周期;

測試三中:
驗證了執(zhí)行線程池并行執(zhí)行的效果


源碼分析

AsyncTask開始執(zhí)行工作的入口函數(shù)為AsyncTask.execute,所以從該方法入手查看

AsyncTask源碼

execute函數(shù)

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

注解上也表明該方法運行需要在ui線程運行,為什么需要呢穴肘?此為問題一歇盼;

這邊使用execute觸發(fā)會使用默認(rèn)的線程池SerialExecutor sDefaultExecutor,
該線程池實際上只起到一個隊列控制评抚,保存task依次按順序執(zhí)行豹缀;
假設(shè)需要并發(fā)執(zhí)行AsyncTask,則可以直接使用executeOnExecutor方法
傳入合適的線程池就可以達(dá)到效果慨代;

接著查看調(diào)用的executeOnExecutor所執(zhí)行的操作
executeOnExecutor函數(shù)
@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;
}
  • 首先該方法會進(jìn)行一個AsyncTask狀態(tài)的判斷,如果該AsyncTask已經(jīng)運行過或者正在運行則拋出異常邢笙,
    每個AsyncTask只允許直接或者間接調(diào)用一次executeOnExecutor;

  • 狀態(tài)判斷AsyncTask尚處于等待狀態(tài)Status.PENDING,則將該狀態(tài)標(biāo)識為Status.RUNNING正在運行狀態(tài)等待后續(xù)線程池排隊執(zhí)行侍匙;

  • 注意氮惯,接著立即執(zhí)行onPreExecute()方法,也就是用于初始化ui控件準(zhǔn)備工作的方法;
    這邊說明了前面2個問題:

    • 1想暗、onPreExecute()方法在execute()方法調(diào)用后會立即執(zhí)行;
    • 2妇汗、execute()假設(shè)在非ui線程調(diào)用,則onPreExecute()也在非ui線程執(zhí)行说莫,將導(dǎo)致拋出更新ui異常,此為上述問題一,需要要求execute或或者executeOnExecutor在ui線程執(zhí)行;
    • 3杨箭、雖然注解和源碼注釋要求要在ui線程執(zhí)行execute()或者executeOnExecutor,但假設(shè)你沒有重寫onPreExecute()進(jìn)行ui操作(默認(rèn)是空操作),是可以在子線程中執(zhí)行的(可能IDE會有提示錯誤储狭,但運行的時候沒出現(xiàn)異常)互婿,當(dāng)然強(qiáng)烈建議執(zhí)行線程和注解一致
    mWorker.mParams = params;
    exec.execute(mFuture);

然后將傳入的params參數(shù)賦值給mWorker.mParams(params后續(xù)會傳遞給doInBackground進(jìn)行處理),調(diào)用線程池exec處理mFuture;

這邊需要對mWorker、mFuture和線程池exec進(jìn)行分析,首先對于exec可以看出傳入的是線程池SerialExecutor

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

對于線程池SerialExecutor

  • 通過上述分析知道SERIAL_EXECUTOR的定義是靜態(tài)的辽狈,也就是類共享的慈参,同一進(jìn)程共用一個線程池,
  • 下面分析會知道SERIAL_EXECUTOR主要用來維護(hù)asynctask任務(wù)隊列,按先進(jìn)先出的原則順序取出任務(wù)交給實際執(zhí)行的線程池THREAD_POOL_EXECUTOR進(jìn)行執(zhí)行
  • 對于THREAD_POOL_EXECUTOR也是靜態(tài)的,并且執(zhí)行完一個后才會處理下一個任務(wù)刮萌;
  • 因此如果同時創(chuàng)建多個AsyncTask后使用execute進(jìn)行執(zhí)行驮配,默認(rèn)是加入到SERIAL_EXECUTOR進(jìn)行排隊等待執(zhí)行的,一個時刻只有一個AsyncTask在執(zhí)行;
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());
    }
};

//實際執(zhí)行任務(wù)的線程池,注意是靜態(tài)的僧凤,所以AsyncTask共用
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);
    threadPoolExecutor.allowCoreThreadTimeOut(true);
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
    
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();        //即調(diào)用 FutureTask mFuture.run()方法    
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
            //THREAD_POOL_EXECUTOR為實際執(zhí)行任務(wù)的線程池
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

可以看出該SerialExecutor在被調(diào)用execute后畜侦,會將一個任務(wù)添加到隊列ArrayDeque中(即前面exec.execute(mFuture)),execute傳入的是實現(xiàn)了Runnable接口的類FutureTask的實例mFuture,SerialExecutor的主要作用實際上時維護(hù)任務(wù)的隊列躯保,按順序取出任務(wù)交給實際執(zhí)行任務(wù)的線程池THREAD_POOL_EXECUTOR

第一個執(zhí)行時mActive == null所以會調(diào)用scheduleNext,(按先進(jìn)先出)從隊列中拿出一個任務(wù)交給線程池THREAD_POOL_EXECUTOR進(jìn)行執(zhí)行:

  public void run() {
        try {
            r.run();        //即調(diào)用 FutureTask mFuture.run()方法    
        } finally {
            scheduleNext(); //執(zhí)行完畢后旋膳,獲取下一個任務(wù)進(jìn)行處理
        }
    }

執(zhí)行的即為傳入的mFuture.run()方法,執(zhí)行完成后會再次調(diào)用scheduleNext獲取并執(zhí)行下一個AsyncTask任務(wù)途事。
下面看一下FutureTask.run()方法所做的操作

FutureTask類

//FutureTask類構(gòu)造函數(shù),這邊傳入的實際上是實現(xiàn)了Callable接口的WorkerRunnable類對象mWorker
//mWorker與mFuture的關(guān)聯(lián)在AsyncTask創(chuàng)建時構(gòu)造函數(shù)中完成
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}

//線程池THREAD_POOL_EXECUTOR中執(zhí)行的方法
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();   //調(diào)用的是mWorker的call方法
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

由上述可知验懊,線程池THREAD_POOL_EXECUTOR中執(zhí)行的mFuture.run()方法中實際上會調(diào)用result = c.call()即實現(xiàn)了Callable接口的類的WorkerRunnable對象mWorker.call();

其中WorkerRunnable類對象mWorker、FutureTask類對象mFuture的創(chuàng)建和關(guān)聯(lián)位于AsyncTask構(gòu)造函數(shù)中尸变;

AsyncTask構(gòu)造函數(shù)

    //部分需要聯(lián)系使用的成員變量
    //注意是靜態(tài)的,類共享一個線程池
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    //注意是靜態(tài)的變量,類共享一個handler
    private static InternalHandler sHandler;                        

    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;
    private final Handler mHandler;
    
    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        this((Looper) null);
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    public AsyncTask(@Nullable Handler handler) {
        this(handler != null ? handler.getLooper() : null);
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    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); //線程池中最終執(zhí)行doInBackground
                    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);
                }
            }
        };
    }

由上可以看出默認(rèn)構(gòu)造函數(shù)會執(zhí)行

public AsyncTask(@Nullable Looper callbackLooper),傳入?yún)?shù)為null,
此時mHandler = getMainHandler()獲取到一個主線程的handler;
創(chuàng)建了mWorker和mFuture對象义图,并通過mFuture = new FutureTask<Result>(mWorker)
完成mFuture與mWorker的一個關(guān)聯(lián);

后續(xù),線程池THREAD_POOL_EXECUTOR中執(zhí)行的mFuture.run()會執(zhí)行到mWorker.call()由上可看出:

    try {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            result = doInBackground(mParams); //線程池中最終執(zhí)行doInBackground
            Binder.flushPendingCommands();
        } catch (Throwable tr) {
            mCancelled.set(true);
            throw tr;
        } finally {
            postResult(result);
        }

觸發(fā)執(zhí)行了doInBackground(mParams)后召烂,通過postResult(result)將結(jié)果result通過hander發(fā)出最終在handler的ui線程中觸發(fā)了onPostExecute回調(diào);

postResult函數(shù)

private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
使用handler發(fā)送處理結(jié)束的消息

getMainHandler函數(shù)

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

該方法簡單的創(chuàng)建一個handler通過Looper.getMainLooper()使得該handler運行于ui線程,注意的是sHandler是靜態(tài)的碱工,也就是說進(jìn)程所有的AsyncTask共享一個handler進(jìn)行處理消息;

InternalHandler類和finish方法

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) {
            //接收消息并且在ui線程回調(diào)執(zhí)行finish最終調(diào)用onPostExecute方法
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
            //接收消息并且在ui線程回調(diào)執(zhí)行onProgressUpdate方法
                case MESSAGE_POST_PROGRESS:    
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
  • 該handler主要用于接收消息MESSAGE_POST_PROGRESS后在ui線程執(zhí)行onProgressUpdate方法,
    或者接收MESSAGE_POST_RESULT后,最終在ui線程執(zhí)行onPostExecute/onCancelled方法,

  • AsyncTask中2個重要的方法onProgressUpdate奏夫、onPostExecute由該handler執(zhí)行怕篷;

    private void finish(Result result) {
        if (isCancelled()) {
      //任務(wù)執(zhí)行完之后,如果用戶之前調(diào)用了AsyncTask.cancle()則觸發(fā)onCancelled
            onCancelled(result);
        } else {
      //否則觸發(fā)onPostExecute
            onPostExecute(result);  
        }
        mStatus = Status.FINISHED;
    }

源碼總結(jié)

  • 1.AsyncTask中存在靜態(tài)的2個線程池SerialExecutor酗昼、ThreadPoolExecutor廊谓,以及一個靜態(tài)的ui線程的handler
SerialExecutor implements Executor :    sDefaultExecutor
ThreadPoolExecutor :                    THREAD_POOL_EXECUTOR:
進(jìn)程中對于使用execute開始的所有的AsyncTask順序排隊執(zhí)行
  • 2.AsyncTask構(gòu)造函數(shù)中,初始化了handler麻削,WorkerRunnable mWorker蒸痹,F(xiàn)utureTask mFuture,并且將mWorker關(guān)聯(lián)到mFuture:
  mWorker = new WorkerRunnable<Params, Result>(){..}..
  mFuture = new FutureTask<Result>(mWorker) {..}..
  • 3.使用execute的時候:

    • 會調(diào)用executeOnExecutor()并傳遞SerialExecutor
    • 在executeOnExecutor()中執(zhí)行onPreExecute呛哟,并將mFuture傳遞給SerialExecutor進(jìn)行排隊
    • SerialExecutor按先進(jìn)先出的順序依次取出任務(wù)給ThreadPoolExecutor進(jìn)行處理叠荠,處理調(diào)用的是mFuture.run()方法實際上會執(zhí)行到mWorker.call()里面的doInBackground方法,執(zhí)行完成后通過handler觸發(fā)onPostExecute方法;
  • 過程中如果調(diào)用publishProgress會通過handler觸發(fā)onProgressUpdate;

  • 如果要并行執(zhí)行asynctask則不使用execute而是直接使用executeOnExecutor傳遞給合適的線程池竖共,跳過SerialExecutor的排隊步驟;

掃描關(guān)注微信公眾號:


qrcode_for_gh_1bbc19ef669d_258.jpg
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蝙叛,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子公给,更是在濱河造成了極大的恐慌借帘,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淌铐,死亡現(xiàn)場離奇詭異肺然,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)腿准,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門际起,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拾碌,“玉大人,你說我怎么就攤上這事街望⌒O瑁” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵灾前,是天一觀的道長防症。 經(jīng)常有香客問我,道長哎甲,這世上最難降的妖魔是什么蔫敲? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮炭玫,結(jié)果婚禮上奈嘿,老公的妹妹穿的比我還像新娘。我一直安慰自己吞加,他們只是感情好裙犹,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著榴鼎,像睡著了一般伯诬。 火紅的嫁衣襯著肌膚如雪晚唇。 梳的紋絲不亂的頭發(fā)上巫财,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機(jī)與錄音哩陕,去河邊找鬼平项。 笑死,一個胖子當(dāng)著我的面吹牛悍及,可吹牛的內(nèi)容都是我干的闽瓢。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼心赶,長吁一口氣:“原來是場噩夢啊……” “哼扣讼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缨叫,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤椭符,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后耻姥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體销钝,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年琐簇,在試婚紗的時候發(fā)現(xiàn)自己被綠了蒸健。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖似忧,靈堂內(nèi)的尸體忽然破棺而出渣叛,到底是詐尸還是另有隱情,我是刑警寧澤盯捌,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布诗箍,位于F島的核電站,受9級特大地震影響挽唉,放射性物質(zhì)發(fā)生泄漏滤祖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一瓶籽、第九天 我趴在偏房一處隱蔽的房頂上張望匠童。 院中可真熱鬧,春花似錦塑顺、人聲如沸汤求。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扬绪。三九已至,卻和暖如春裤唠,著一層夾襖步出監(jiān)牢的瞬間挤牛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工种蘸, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留墓赴,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓航瞭,卻偏偏與公主長得像诫硕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子刊侯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

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