對AsyncTask的源碼解讀

爲什麼討論AsyncTask?

對AsyncTask的使用我們應該很熟悉了,我們經常使用它來執行一個異步任務,然後在主線程當中更新UI。另外還有兩種HandlerThread和IntentService也可以用來執行異步任務,只不過他們之間稍有區別。這裏討論AsyncTask是因爲我們在平時的面試當中經常被問到,當然,作爲一個進階的開發者是應該搞清楚它的原理,所以寫下這篇博客爲了加深下自己的印象。

AsyncTask

AsyncTask應該是我們最常用的一個異步抽象類了。它有幾個方法:


下面我們將從源碼上面對這幾個方法進行一 一介紹,看看他們直接到底做了哪些操作。

通過源碼可以看出AsyncTask是一個抽象類,這個抽象類中有幾個泛型參數,這些泛型其實就是約束了上面幾個方法的返回類型,如果當前方法沒有返回類型,就直接傳入Void.

我們在使用的時候會new一個繼承AsyncTask的類的對象,然後調用execute()方法,所以我們就從AsyncTask的構造函數入手


構造函數當中,創建了一個WorkerRunnable,並在Call方法中引用了doInBackground()的執行結果,然後交由FutureTask執行。這種創建線程的方式是不是很熟悉?創建線程我們稍微回顧一下:

  • 繼承Thread
  • 實現Runnable
  • 實現Callable,實現Callable是可以將線程的執行結果通過FutureTask對象mFuture.get()到。這裏創建WorkerRunnable的方式就是使用了第三種這種創建線程的方式。請看源碼:


所以從這裏就能夠看出doInBackground是在子線程中執行的

翻看源碼會發現,上述標藍的地方最終調用的也是postResult(稍後我們解釋下這個方法的作用),那這裏是不是和標紅的地方重複調用了?

答案顯然不是,這裏AutomicBoolean變量進行了控制

這樣在postResultIfNotInvoked中就不會重複調用了。

ok,創建好了FutureTask對象之後,那這個對象實在什麼時機調用的呢?繼續翻閱代碼看一下execute是如何執行這個任務的

execute中是可以傳入可變參數的,這些可變參數又傳入到了WorkerRunnable中的mPrams,最終傳入到了doInBackground()方法當中。execute方法又調用了executeOnExecutor方法,這個方法當中多了一個參數sDefaultExecutor,這個參數是什麼意思?

下面就看一下這個SerialExecutor是什麼?


其實就是實現了一個Executor接口,然後在execute當中將Runnable任務放到一個隊列當中,最終通過scheduleNext()方法執行這個隊列當中的任務,那scheduleNext()方法當中有一個THREAD_POOL_EXECUTOR,這又是什麼?

通過翻閱代碼,發現其實THREAD_POOL_EXECUTOR就是一個線程池!

那麼下面看一下這個executeOnExecutor方法當中具體幹了些什麼?


其實這個方法當中先調用了onPreExecute()方法,因爲這個方法是運行在主線程當中,而且是在execute方法之前調用的,所以我們常在onPreExecute()方法當中做一些異步之前的準備工作。然後又通過線程池執行了我們在構造函數當中創建的FutureTask。執行完之後,將結果傳遞到postResult當中

你看,其實最終子線程和主線程的交互還是通過Handler傳遞。下面我們就看一下這個Handler

最終子線程的處理結果交由handlerMessage處理,result.mTask其實就是AsyncTask,那麼我們就看一下這個finish方法

finish方法最終調用了onPostExecute(result),所以我們在繼承AsyncTask方法的時候,在這個方法處理我們異步執行的結果。到這裏整個AsyncTask的執行過程基本就結束了。這裏稍微屢一下:

  • 在AsyncTask構造函數當中創建我們的子線程WorkerRunnable,也就是我們要處理的異步任務doInBackground
  • 然後調用execute方法,將這個異步任務交由THREAD_POOL_EXECUTOR線程池去處理,並在任務執行之前調用了onPreExecute()
  • 將WorkerRunnable中的結果通過線程池執行後,通過Handler的方式交由主線程中的onPostExecute()方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章