AsyncTask分析

今天來分析一下AsyncTask,并開始嘗試閱讀Google源碼工程師寫的文檔.全英文,顯然是一項(xiàng)挑戰(zhàn),來吧。因?yàn)橹耙矝]寫過源碼分析的文章,看的也比較少,所以如果結(jié)構(gòu)混亂,原諒我不是故意的。


AsyncTask源碼在源碼目錄的framework/base/core/java/android/os目錄下,在具體代碼之前,有詳細(xì)的英文說明文檔。這篇文章就出自此處。

一、說明

AsyncTask是Anroid系統(tǒng)提供給我們的在UI線程中使用該類,來進(jìn)行執(zhí)行后臺(tái)執(zhí)行長(zhǎng)時(shí)間的操作,并將執(zhí)行結(jié)果更新到UI線程中;是除了使用Thread和Handler來實(shí)現(xiàn)耗時(shí)操作和結(jié)果更新的另一種實(shí)現(xiàn),更簡(jiǎn)單,方便。

  • 定義說明:定義一個(gè)異步的AsyncTask任務(wù)時(shí),系統(tǒng)允許傳遞3個(gè)屬性類型來進(jìn)行說明,Params,Progress,Result;按其執(zhí)行順序依次對(duì)應(yīng),執(zhí)行前需傳入的參數(shù),執(zhí)行中進(jìn)度的更新單位,執(zhí)行完成之后返回的結(jié)果類型;使用時(shí)可傳入String,Long,Integer等類型的參數(shù),如果不需要參數(shù),使用時(shí)可傳Void。
  • 執(zhí)行過程說明:AsyncTask執(zhí)行的過程主要設(shè)計(jì)開發(fā)者的就是4個(gè)方法,也可以理解為4步:依次為onPreExecute,doInBackground,onProgressUpdate,onPostExecute。其中只有doInBackground方法是在非UI線程中執(zhí)行的,其他三個(gè)均在UI線程中執(zhí)行,極大的方便了開發(fā)者的使用。
二、用法

AsyncTask類在源碼中被定義成了抽象類,如果開發(fā)者想要使用AsyncTask,必須要自己實(shí)現(xiàn)一個(gè)自定義任務(wù)類來extends源碼,然后進(jìn)行使用。自定義任務(wù)類應(yīng)至少實(shí)現(xiàn)doInBackground方法,因?yàn)槠涫浅殚e的。通常的情況下,還會(huì)實(shí)現(xiàn)onPostExecute方法,onPreExecute方法等。
舉例:

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

一旦一個(gè)任務(wù)被創(chuàng)建,開始執(zhí)行該任務(wù),僅需調(diào)用其execute方法即可執(zhí)行。

  • 執(zhí)行任務(wù)實(shí)例,執(zhí)行任務(wù)分為串行和并行兩種形式,如下:
new DownAsyncTask().extcute();//串行實(shí)例化
new DownAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");//并行實(shí)例化
  • 取消一個(gè)任務(wù):一個(gè)任務(wù)可以在執(zhí)行期間的任何時(shí)刻被取消,只需要調(diào)用其cancel方法,調(diào)用cancel方法之后,isCancelled方法就會(huì)返回true,表示該任務(wù)已取消;在調(diào)用cancel方法之后,doInBackground方法結(jié)束執(zhí)行之后,會(huì)調(diào)用onCancelled方法,不在執(zhí)行onPostExecute方法;
三、使用規(guī)則謹(jǐn)記
  • 目標(biāo)任務(wù)必須在UI線程中進(jìn)行加載;
  • 目標(biāo)任務(wù)實(shí)例必須在UI線程中進(jìn)行創(chuàng)建;
  • 開發(fā)者不能手動(dòng)調(diào)用onPreExecute,onPostExecute,doInBackground,onProgressUpdate方法;
  • 目標(biāo)任務(wù)僅僅會(huì)執(zhí)行一次,如果試圖執(zhí)行多次,系統(tǒng)會(huì)拋出異常
四、執(zhí)行規(guī)則
  • 起初剛開始設(shè)計(jì)時(shí),AsyncTask僅會(huì)在后臺(tái)單獨(dú)的線程中進(jìn)行執(zhí)行,也就是說執(zhí)行是串行的;
  • 從SDK1.6開始,開始轉(zhuǎn)變?yōu)樵谝粋€(gè)線程池中允許多個(gè)任務(wù)進(jìn)行請(qǐng)求執(zhí)行,也就是支持并行執(zhí)行;
  • 從3.1開始,又修改為目標(biāo)任務(wù)在一個(gè)單線程中執(zhí)行,也就是串行執(zhí)行,主要是為了避免并發(fā)執(zhí)行可能會(huì)造成的錯(cuò)誤;如果實(shí)在想并發(fā)執(zhí)行,可以調(diào)用executeOnExecutor方法進(jìn)行;

以上的內(nèi)容均來在AsyncTask源碼聲明文件前的注釋,從中也可以看到,人家Google確實(shí)是偉大的公司,標(biāo)準(zhǔn)規(guī)范特別詳細(xì),特別貼心。

五、代碼分析
  • 關(guān)于線程池的配置
//獲取到當(dāng)前設(shè)備的cpu配置
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//核心線程數(shù)量 動(dòng)態(tài)的計(jì)算 
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
//線程池中允許的最大線程數(shù)目
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
  • 關(guān)于任務(wù)狀態(tài)
    一個(gè)目標(biāo)任務(wù)在其完整的生命周期內(nèi),其任意時(shí)刻的狀態(tài)僅會(huì)是一下三種中的一種:
public enum Status {
        //任務(wù)未執(zhí)行
        PENDING,
        //任務(wù)正在執(zhí)行中
        RUNNING,
        //任務(wù)已結(jié)束
        FINISHED,
    }
  • 構(gòu)造函數(shù)中的初始化工作
public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                //設(shè)置線程的優(yōu)先級(jí)
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                //調(diào)用doInBackground方法,并將postResult進(jìn)行回傳分發(fā)
                return postResult(doInBackground(mParams));
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            //任務(wù)執(zhí)行完畢后會(huì)調(diào)用done方法
            @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 occured while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
      };
}
//初始化操作中涉及到的mWorker變量的類聲明,該WorkerRunnable實(shí)現(xiàn)了Callable接口,使用時(shí)實(shí)現(xiàn)call方法
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }

//初始化操作中涉及到的get()方法,該方法返回的就是執(zhí)行后的結(jié)果,也就是mWorker的call方法的返回值
public final Result get() throws InterruptedException, ExecutionException {
        return mFuture.get();
    }

  • 執(zhí)行過程分析
    1在主線程中實(shí)例化任務(wù)對(duì)象并顯示調(diào)用execute方法。
    /**
     * An {@link Executor} that executes tasks one at a time in serial
     * order.  This serialization is global to a particular process.
     * 全局的線程池用來執(zhí)行隊(duì)列任務(wù)
     */
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

    //This method must be invoked on the UI thread.方法注釋說明該方法必須在UI線程調(diào)用
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        //調(diào)用executeOnExecutor方法執(zhí)行后臺(tái)任務(wù)
        return executeOnExecutor(sDefaultExecutor, params);
    }

2.執(zhí)行線程池對(duì)象的execute方法,具體執(zhí)行某一個(gè)隊(duì)列任務(wù).

    //包含兩個(gè)參數(shù),第一個(gè)參數(shù)為默認(rèn)的線程池對(duì)象,默認(rèn)已經(jīng)初始化;第二個(gè)參數(shù)為具體任務(wù)的傳入?yún)?shù)
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        //執(zhí)行之前首先判斷任務(wù)的狀態(tài),只有是PENDING狀態(tài)才能執(zhí)行,這里也照應(yīng)了前文說的,一個(gè)目標(biāo)任務(wù)只能被執(zhí)行一次,否則會(huì)拋出異常;
        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)");
            }
        }
        //將目標(biāo)任務(wù)的狀態(tài)設(shè)置為正在執(zhí)行
        mStatus = Status.RUNNING;
        //調(diào)用onPreExecute方法,注意此時(shí)還在UI線程中
        onPreExecute();
        //將任務(wù)傳入?yún)?shù)進(jìn)行賦值,調(diào)用execute方法執(zhí)行耗時(shí)操作;同時(shí)返回為AsyncTask對(duì)象任務(wù)自身;
        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

3.具體的execute方法

    //變量定義
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    //Executor 聲明及實(shí)現(xiàn)
    private static class SerialExecutor implements Executor {
        //任務(wù)線程隊(duì)列
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
        
        //上一步驟提到的execute方法,參數(shù)說明傳入一個(gè)Runnable對(duì)象
        public synchronized void execute(final Runnable r) {
            //將此任務(wù)添加到任務(wù)隊(duì)列中
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        //此處調(diào)用的run方法就是調(diào)用的傳入的mFuture對(duì)象的run方法
                        r.run();
                    } finally {
                        //try...finally代碼塊,finally塊一定會(huì)執(zhí)行,處理隊(duì)列中的下一個(gè)任務(wù)
                        scheduleNext();
                    }
                }
            });
            //如果沒有活動(dòng)的runnable,從雙端隊(duì)列里面取出一個(gè)runnable放到線程池中運(yùn)行
            //第一個(gè)請(qǐng)求任務(wù)過來的時(shí)候mActive是空的
            if (mActive == null) {
                scheduleNext();
            }
        }
        
        //具體處理下一個(gè)任務(wù)的方法
        protected synchronized void scheduleNext() {
            //從隊(duì)列中取一個(gè)任務(wù) 然后執(zhí)行線程池的execute方法
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
    
    //線程池對(duì)象
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

4.關(guān)于mFuture以及具體的線程執(zhí)行和方法調(diào)用

    //上文已經(jīng)提到過的繼承自Callable接口的自定義類,同時(shí)添加了Params數(shù)組參數(shù);
    private final WorkerRunnable<Params, Result> mWorker;
    //具體的任務(wù)線程對(duì)象
    private final FutureTask<Result> mFuture;
    
    //Java庫中的FutureTask聲明及定義,實(shí)現(xiàn)了RunnableFuture接口,RunnableFuture接口繼承自Runnable,這也是上一步驟的execute要傳入的對(duì)象mFeature的原因,我們主要看run方法。
    public class FutureTask<V> implements RunnableFuture<V> {
        public void run() {    
          if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
            return;    
          try {   
             //此處涉及到了一個(gè)Callable對(duì)象     
             Callable<V> c = callable;        
             if (c != null && state == NEW) { 
               V result;
               boolean ran;
               try { 
                 //調(diào)用Callable的call方法。這里就明白為什么我們要看這段代碼了,就是因?yàn)槲覀円矍宕a執(zhí)行的順序及調(diào)用關(guān)系。
                 //在執(zhí)行run方法的時(shí)候,會(huì)回調(diào)call方法,其實(shí)就是我們AsyncTask類中以及上文分析的在構(gòu)造方法中初始化操作的mWorkRunnable匿名內(nèi)部類的call方法,然后執(zhí)行其耗時(shí)操作。
                 //當(dāng)執(zhí)行完成時(shí)再調(diào)用done方法,進(jìn)行結(jié)果分發(fā)。
                 result = c.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);
          }
      }
   }

上面的兩個(gè)步驟比較關(guān)鍵,解析完代碼,重新用文字進(jìn)行梳理一下,具體來說就是:exec.execute(mFuture)執(zhí)行時(shí),SerialExecutor將實(shí)現(xiàn)了Runnable以及RunnableFeture接口的mFuture傳遞給實(shí)例對(duì)象執(zhí)行execute方法。在execute方法中,首先將任務(wù)添加到任務(wù)隊(duì)列中,添加方法為mTasks.offer(Runnable r);然后開始執(zhí)行任務(wù),第一次執(zhí)行時(shí)mActive==null,所以直接從任務(wù)隊(duì)列中取一個(gè)任務(wù)并調(diào)用線程池的execute方法,其實(shí)就是mFuture的run方法,從任務(wù)隊(duì)列取任務(wù)的方法為mTasks.poll()方法;上一個(gè)任務(wù)執(zhí)行完run方法之后,接著處理下一個(gè)任務(wù),依次循環(huán);在執(zhí)行mFeture的run方法時(shí),也就是子線程開始執(zhí)行時(shí),會(huì)回調(diào)call方法,call方法就是上文的mWorkRunnable中的call,從而call方法中又調(diào)用了doInBackground方法執(zhí)行耗時(shí)操作; doInBackground方法執(zhí)行完畢后,會(huì)調(diào)用postResult方法將結(jié)果分發(fā)回傳。

  1. postResult方法以及子線程如何通知主線程的分析
private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
private static InternalHandler sHandler;
//使用了單例模式來保證Handler唯一
private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }
private static class InternalHandler extends Handler {
        public InternalHandler() {
            //獲取到UI線程的Looper()
            super(Looper.getMainLooper());
        }

        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                //結(jié)果消息分發(fā)
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                //進(jìn)度消息分發(fā)
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

至此,AsyncTask源碼大概的內(nèi)容就是這些。歡迎評(píng)論交流。

掃描下方的二維碼,加入關(guān)注,所發(fā)布的博客文章會(huì)及時(shí)發(fā)布到公眾號(hào),方便及時(shí)查看,加入我吧,一起進(jìn)步。

喜歡而非堅(jiān)持
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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