當前位置:編程學習大全網 - 源碼下載 - Android 中的“子線程”解析

Android 中的“子線程”解析

Android 中線程可分為 主線程 和 子線程 兩類,其中主線程也就是 UI線程 ,它的主要這作用就是運行四大組件、處理界面交互。子線程則主要是處理耗時任務,也是我們要重點分析的。

首先 Java 中的各種線程在 Android 裏是通用的,Android 特有的線程形態也是基於 Java 的實現的,所以有必要先簡單的了解下 Java 中的線程,本文主要包括以下內容:

在 Java 中要創建子線程可以直接繼承 Thread 類,重寫 run() 方法:

或者實現 Runnable 接口,然後用Thread執行Runnable,這種方式比較常用:

簡單的總結下:

Callable 和 Runnable 類似,都可以用來處理具體的耗時任務邏輯的,但是但具體的差別在哪裏呢?看壹個小例子:

定義 MyCallable 實現了 Callable 接口,和之前 Runnable 的 run() 方法對比下, call() 方法是有返回值的哦,泛型就是返回值的類型:

壹般會通過線程池來執行 Callable (線程池相關內容後邊會講到),執行結果就是壹個 Future 對象:

可以看到,通過線程池執行 MyCallable 對象返回了壹個 Future 對象,取出執行結果。

Future 是壹個接口,從其內部的方法可以看出它提供了取消任務(有坑!!!)、判斷任務是否完成、獲取任務結果的功能:

Future 接口有壹個 FutureTask 實現類,同時 FutureTask 也實現了 Runnable 接口,並提供了兩個構造函數:

用 FutureTask 壹個參數的構造函數來改造下上邊的例子:

FutureTask 內部有壹個 done() 方法,代表 Callable 中的任務已經結束,可以用來獲取執行結果:

所以 Future + Callable 的組合可以更方便的獲取子線程任務的執行結果,更好的控制任務的執行,主要的用法先說這麽多了,其實 AsyncTask 內部也是類似的實現!

註意, Future 並不能取消掉運行中的任務,這點在後邊的 AsyncTask 解析中有提到。

Java 中線程池的具體的實現類是 ThreadPoolExecutor ,繼承了 Executor 接口,這些線程池在 Android 中也是通用的。使用線程池的好處:

常用的構造函數如下:

壹個常規線程池可以按照如下方式來實現:

執行任務:

基於 ThreadPoolExecutor ,系統擴展了幾類具有新特性的線程池:

線程池可以通過 execute() 、 submit() 方法開始執行任務,主要差別從方法的聲明就可以看出,由於 submit() 有返回值,可以方便得到任務的執行結果:

要關閉線程池可以使用如下方法:

IntentService 是 Android 中壹種特殊的 Service,可用於執行後臺耗時任務,任務結束時會自動停止,由於屬於系統的四大組件之壹,相比壹般線程具有較高的優先級,不容易被殺死。用法和普通 Service 基本壹致,只需要在 onHandleIntent() 中處理耗時任務即可:

至於 HandlerThread,它是 IntentService 內部實現的重要部分,細節內容會在 IntentService 源碼中說到。

IntentService 首次創建被啟動的時候其生命周期方法 onCreate() 會先被調用,所以我們從這個方法開始分析:

這裏出現了 HandlerThread 和 ServiceHandler 兩個類,先搞明白它們的作用,以便後續的分析。

首先看 HandlerThread 的核心實現:

首先它繼承了 Thread 類,可以當做子線程來使用,並在 run() 方法中創建了壹個消息循環系統、開啟消息循環。

ServiceHandler 是 IntentService 的內部類,繼承了 Handler,具體內容後續分析:

現在回過頭來看 onCreate() 方法主要是壹些初始化的操作, 首先創建了壹個 thread 對象,並啟動線程,然後用其內部的 Looper 對象 創建壹個 mServiceHandler 對象,將子線程的 Looper 和 ServiceHandler 建立了綁定關系,這樣就可以使用 mServiceHandler 將消息發送到子線程去處理了。

生命周期方法 onStartCommand() 方法會在 IntentService 每次被啟動時調用,壹般會這裏處理啟動 IntentService 傳遞 Intent 解析攜帶的數據:

又調用了 start() 方法:

就是用 mServiceHandler 發送了壹條包含 startId 和 intent 的消息,消息的發送還是在主線程進行的,接下來消息的接收、處理就是在子線程進行的:

當接收到消息時,通過 onHandleIntent() 方法在子線程處理 intent 對象, onHandleIntent() 方法執行結束後,通過 stopSelf(msg.arg1) 等待所有消息處理完畢後終止服務。

為什麽消息的處理是在子線程呢?這裏涉及到 Handler 的內部消息機制,簡單的說,因為 ServiceHandler 使用的 Looper 對象就是在 HandlerThread 這個子線程類裏創建的,並通過 Looper.loop() 開啟消息循環,不斷從消息隊列(單鏈表)中取出消息,並執行,截取 loop() 的部分源碼:

dispatchMessage() 方法間接會調用 handleMessage() 方法,所以最終 onHandleIntent() 就在子線程中劃線執行了,即 HandlerThread 的 run() 方法。

這就是 IntentService 實現的核心,通過 HandlerThread + Hanlder 把啟動 IntentService 的 Intent 從主線程切換到子線程,實現讓 Service 可以處理耗時任務的功能!

AsyncTask 是 Android 中輕量級的異步任務抽象類,它的內部主要由線程池以及 Handler 實現,在線程池中執行耗時任務並把結果通過 Handler 機制中轉到主線程以實現UI操作。典型的用法如下:

從 Android3.0 開始,AsyncTask 默認是串行執行的:

如果需要並行執行可以這麽做:

AsyncTask 的源碼不多,還是比較容易理解的。根據上邊的用法,可以從 execute() 方法開始我們的分析:

看到 @MainThread 註解了嗎?所以 execute() 方法需要在主線程執行哦!

進而又調用了 executeOnExecutor() :

可以看到,當任務正在執行或者已經完成,如果又被執行會拋出異常!回調方法 onPreExecute() 最先被執行了。

傳入的 sDefaultExecutor 參數,是壹個自定義的串行線程池對象,所有任務在該線程池中排隊執行:

可以看到 SerialExecutor 線程池僅用於任務的排隊, THREAD_POOL_EXECUTOR 線程池才是用於執行真正的任務,就是我們線程池部分講到的 ThreadPoolExecutor :

再回到 executeOnExecutor() 方法中,那麽 exec.execute(mFuture) 就是觸發線程池開始執行任務的操作了。

那 executeOnExecutor() 方法中的 mWorker 是什麽? mFuture 是什麽?答案在 AsyncTask 的構造函數中:

原來 mWorker 是壹個 Callable 對象, mFuture 是壹個 FutureTask 對象,繼承了 Runnable 接口。所以 mWorker 的 call() 方法會在 mFuture 的 run() 方法中執行,所以 mWorker 的 call() 方法在線程池得到執行!

同時 doInBackground() 方法就在 call() 中方法,所以我們自定義的耗時任務邏輯得到執行,不就是我們第二部分講的那壹套嗎!

doInBackground() 的返回值會傳遞給 postResult() 方法:

就是通過 Handler 將最終的耗時任務結果從子線程發送到主線程,具體的過程是這樣的, getHandler() 得到的就是 AsyncTask 構造函數中初始化的 mHandler , mHander 又是通過 getMainHandler() 賦值的:

可以在看到 sHandler 是壹個 InternalHandler 類對象:

所以 getHandler() 就是在得到在主線程創建的 InternalHandler 對象,所以

就可以完成耗時任務結果從子線程到主線程的切換,進而可以進行相關UI操作了。

當消息是 MESSAGE_POST_RESULT 時,代表任務執行完成, finish() 方法被調用:

如果任務沒有被取消的話執行 onPostExecute() ,否則執行 onCancelled() 。

如果消息是 MESSAGE_POST_PROGRESS , onProgressUpdate() 方法被執行,根據之前的用法可以 onProgressUpdate() 的執行需要我們手動調用 publishProgress() 方法,就是通過 Handler 來發送進度數據:

進行中的任務如何取消呢?AsyncTask 提供了壹個 cancel(boolean mayInterruptIfRunning) ,參數代表是否中斷正在執行的線程任務,但是呢並不靠譜, cancel() 的方法註釋中有這麽壹段:

大致意思就是調用 cancel() 方法後, onCancelled(Object) 回調方法會在 doInBackground() 之後被執行而 onPostExecute() 將不會被執行,同時妳應該 doInBackground() 回調方法中通過 isCancelled() 來檢查任務是否已取消,進而去終止任務的執行!

所以只能自己動手了:

AsyncTask 整體的實現流程就這些了,源碼是最好的老師,自己跟著源碼走壹遍有些問題可能就豁然開朗了!

  • 上一篇:賽博朋克2077多人遊戲模式玩法講解多人模式拆包內容介紹
  • 下一篇:超級測量柱源代碼
  • copyright 2024編程學習大全網