天天看點

android多線程-AsyncTask之工作原理深入解析(下)

關聯文章: 

<a href="http://blog.csdn.net/javazejian/article/details/52464139" target="_blank">android多線程-AsyncTask之工作原理深入解析(下)</a>

  上篇分析AsyncTask的一些基本用法以及不同android版本下的差別,接着本篇我們就來全面剖析一下AsyncTask的工作原理。在開始之前我們先來了解一個多線程的知識點——Callable&lt;V&gt; 、Future&lt;V&gt;和FutureTask類

Callable的接口定義如下:

  Callable接口聲明了一個名稱為call()的方法,該方法可以有傳回值V,也可以抛出異常。Callable也是一個線程接口,它與Runnable的主要差別就是Callable線上程執行完成後可以有傳回值而Runnable沒有傳回值,Runnable接口聲明如下:

submit(Callable task),傳遞一個實作Callable接口的任務,并且傳回封裝了異步計算結果的Future。

submit(Runnable task, T result),傳遞一個實作Runnable接口的任務,并且指定了在調用Future的get方法時傳回的result對象。

submit(Runnable task),傳遞一個實作Runnable接口的任務,并且傳回封裝了異步計算結果的Future。

  是以我們隻要建立好我們的線程對象(實作Callable接口或者Runnable接口),然後通過上面3個方法送出給線程池去執行即可。Callable接口介紹就先到這,再來看看Future時什麼鬼。

  Future接口是用來擷取異步計算結果的,說白了就是對具體的Runnable或者Callable對象任務執行的結果進行擷取(get()),取消(cancel()),判斷是否完成等操作。其方法如下:

總得來說Future有以下3點作用:

能夠中斷執行中的任務

判斷任務是否執行完成

擷取任務執行完成後額結果。

  但是Future隻是接口,我們根本無法将其建立為對象,于官方又給我們提供了其實作類FutureTask,這裡我們要知道前面兩個接口的介紹都隻為此類做鋪墊,畢竟AsncyTask中使用到的對象是FutureTask。

先來看看FutureTask的實作:

1

顯然FutureTask類實作了RunnableFuture接口,我們再看一下RunnableFuture接口的實作:

2

3

  從接口實作可以看出,FutureTask除了實作了Future接口外還實作了Runnable接口,是以FutureTask既可以當做Future對象也可是Runnable對象,當然FutureTask也就可以直接送出給線程池來執行。接着我們最關心的是如何建立FutureTask對象,實際上可以通過如下兩個構造方法來建構FutureTask

  從構造方法看出,我們可以把一個實作了Callable或者Runnable的接口的對象封裝成一個FutureTask對象,然後通過線程池去執行,那麼具體如何使用呢?簡單案例,CallableDemo.java代碼如下:

CallableTest.java測試代碼如下:

  代碼非常簡單,注釋也很明朗,這裡我們分析一下第2種執行方式,先前聲明一個CallableDemo類,該類實作了Callable接口,接着通過call方法去計算sum總值并傳回。然後在測試類CallableTest中,把CallableDemo執行個體類封裝成FutureTask對象并交給線程池去執行,最終執行結果将封裝在FutureTask中,通過FutureTask#get()可以擷取執行結果。第一種方式則是直接把Callable實作類丢給線程池執行,其結果封裝在Future執行個體中,第2種方式執行結果如下:

  ok~,到此我們對Callable、Future和FutureTask就介紹到這,有了這個知識鋪墊,我們就可以愉快的撩開AsyncTask的内部工作原理了。

  在上篇中,使用了如下代碼來執行AsyncTask的異步任務:

  從代碼可知,入口是execute方法,那我們就先看看execute的源碼:

  很明顯execute方法隻是一個殼子,直接調用了<code>executeOnExecutor(sDefaultExecutor, params)</code>,其中sDefaultExecutor是一個串行的線程池,接着看看sDefaultExecutor内部實作:

  從源碼可以看出,ArrayDeque是一個存放任務隊列的容器(mTasks),任務Runnable傳遞進來後交給SerialExecutor的execute方法處理,SerialExecutor會把任務Runnable插入到任務隊列mTasks尾部,接着會判斷是否有Runnable在執行,沒有就調用scheduleNext方法去執行下一個任務,接着交給THREAD_POOL_EXECUTOR線程池中執行,由此可見SerialExecutor并不是真正的線程執行者,它隻是是保證傳遞進來的任務Runnable(執行個體是一個FutureTask)串行執行,而真正執行任務的是THREAD_POOL_EXECUTOR線程池,當然該邏輯也展現AsyncTask内部的任務是預設串行進行的。順便看一下THREAD_POOL_EXECUTOR線程池的聲明:

  ok~,關于sDefaultExecutor,我們先了解到這,回到之前execute方法内部調用的executeOnExecutor方法的步驟,先來看看executeOnExecutor都做了些什麼事?其源碼如下:

  從executeOnExecutor方法的源碼分析得知,執行任務前先會去判斷目前AsyncTask的狀态,如果處于RUNNING和FINISHED狀态就不可再執行,直接抛出異常,隻有處于Status.PENDING時,AsyncTask才會去執行。然後onPreExecute()被執行的,該方法可以用于線程開始前做一些準備工作。接着會把我們傳遞進來的參數指派給 mWorker.mParams ,并執行開始執行mFuture任務,那麼mWorker和mFuture到底是什麼?先看看mWorker即WorkerRunnable的聲明源碼:

  WorkerRunnable抽象類實作了Callable接口,是以WorkerRunnable本質上也算一個Callable對象,其内部還封裝了一個mParams的數組參數,是以我們在外部執行execute方法時傳遞的可變參數最終會指派給WorkerRunnable的内部數組mParams,這些參數最後會傳遞給doInBackground方法處理,這時我們發現doInBackground方法也是在WorkerRunnable的call方法中被調用的,看看其源碼如下:

   可以看到在初始化AsyncTask時,不僅建立了mWorker(本質實作了Callable接口的執行個體類)而且也建立了FutureTask對象,并把mWorker對象封裝在FutureTask對象中,最後FutureTask對象将在executeOnExecutor方法中通過線程池去執行。給出下圖協助了解: 

android多線程-AsyncTask之工作原理深入解析(下)

  AsynTask在初始化時會建立mWorker執行個體對象和FutureTask執行個體對象,mWorker是一個實作了Callable線程接口并封裝了傳遞參數的執行個體對象,然後mWorker執行個體會被封裝成FutureTask執行個體中。在AsynTask建立後,我們調用execute方法去執行異步線程,其内部又直接調用了executeOnExecutor方法,并傳遞了線程池exec對象和執行參數,該方法内部通過線程池exec對象去執行mFuture執行個體,這時mWorker内部的call方法将被執行并調用doInBackground方法,最終通過postResult去通知更新結果。關于postResult方法,其源碼如下:

  顯然是通過Handler去執行結果更新的,在執行結果成傳回後,會把result封裝到一個AsyncTaskResult對象中,最後把MESSAGE_POST_RESULT标示和AsyncTaskResult存放到Message中并發送給Handler去處理,這裡我們先看看AsyncTaskResult的源碼:

  顯然AsyncTaskResult封裝了執行結果的數組以及AsyncTask本身,這個沒什麼好說的,接着看看AsyncTaskResult被發送到handler後如何處理的。

  從Handler的源碼分析可知,該handler綁定的線程為主線線程,這也就是為什麼AsyncTask必須在主線程建立并執行的原因了。接着通過handler發送過來的不同标志去決定執行那種結果,如果标示為MESSAGE_POST_RESULT則執行AsyncTask的finish方法并傳遞執行結果給該方法,finish方法源碼如下:

  該方法先判斷任務是否被取消,如果沒有被取消則去執行onPostExecute(result)方法,外部通過onPostExecute方法去更新相關資訊,如UI,消息通知等。最後更改AsyncTask的狀态為已完成。到此AsyncTask的全部流程執行完。 

這裡還有另一種标志MESSAGE_POST_PROGRESS,該标志是我們在doInBackground方法中調用publishProgress方法時發出的,該方法原型如下:

  ok~,AsyncTask的整體流程基本分析完,最後來個總結吧:當我們調用execute(Params… params)方法後,其内部直接調用executeOnExecutor方法,接着onPreExecute()被調用方法,執行異步任務的WorkerRunnable對象(實質為Callable對象)最終被封裝成FutureTask執行個體,FutureTask執行個體将由線程池sExecutor執行去執行,這個過程中doInBackground(Params… params)将被調用(在WorkerRunnable對象的call方法中被調用),如果我們覆寫的doInBackground(Params… params)方法中調用了publishProgress(Progress… values)方法,則通過InternalHandler執行個體sHandler發送一條MESSAGE_POST_PROGRESS消息,更新進度,sHandler處理消息時onProgressUpdate(Progress… values)方法将被調用;最後如果FutureTask任務執行成功并傳回結果,則通過postResult方法發送一條MESSAGE_POST_RESULT的消息去執行AsyncTask的finish方法,在finish方法内部onPostExecute(Result result)方法被調用,在onPostExecute方法中我們可以更新UI或者釋放資源等。這既是AsyncTask内部的工作流程,可以說是Callable+FutureTask+Executor+Handler内部封裝。結尾我們獻上一張執行流程,協助大家了解整個流程: 

android多線程-AsyncTask之工作原理深入解析(下)

好~,本篇到此結束。。。

    本文轉自 一點點征服   部落格園部落格,原文連結:http://www.cnblogs.com/ldq2016/p/8193634.html,如需轉載請自行聯系原作者

繼續閱讀