因為 Android 是使用 Java 開發(fā)的,所以當我們談及 Android 中的多線程,必然繞不過 Java 中的多線程編程。但在這篇文章中,我們不會過多地分析 Java 中的多線程編程的知識。我們會在以后分析 Java 并發(fā)編程的時候分析 Java 中的多線程、線程池和并發(fā) API 的用法。
我們先來總結一下 Android 多線程編程的演變過程:首先是 Java 的 Thread。因為本身在創(chuàng)建一個線程和銷毀一個線程的時候會有一定的開銷,當我們任務的執(zhí)行時間相比于這個開銷很小的時候,單獨創(chuàng)建一個線程就顯得不劃算。所以,當程序中存在大量的、小的任務的時候,建議使用線程池來進行管理。但我們一般也很少主動去創(chuàng)建線程池,這是因為——也許是考慮到開發(fā)者自己去維護一個線程池比較復雜—— Android 中已經(jīng)為我們設計了 AsyncTask。AsyncTask 內部封裝了一個線程池,我們可以使用它來執(zhí)行耗時比較短的任務。但 AsyncTask 也有一些缺點:1).如果你的程序中存在很多的不同的任務的時候,你可能要為每個任務定義一個 AsyncTask 的子類。2).從異步線程切換到主線程的方式不如 RxJava 簡潔。所以,在實際開發(fā)的過程中,我通常使用 RxJava 來實現(xiàn)異步的編程。尤其是局部的優(yōu)化、不值得專門定義一個 AsyncTask 類的時候,RxJava 用起來更加舒服。
上面的多線程創(chuàng)建的只是普通的線程,對系統(tǒng)來說,優(yōu)先級比較低。在 Android 中還提供了 IntentService 來執(zhí)行優(yōu)先級相對較高的任務。啟動一個 IntentService 任務的時候會將任務添加到其內部的、異步的消息隊列中執(zhí)行。此外,IntentService 又繼承自 Service,所以這讓它具有異步和較高的優(yōu)先級兩個優(yōu)勢。
在之前的文章中,我們已經(jīng)分析過 AsyncTask、RxJava 以及用來實現(xiàn)線程切換的 Handler. 這里奉上這些文章的鏈接:
- 《Android AsyncTask 源碼分析》
- 《RxJava2 系列 (1):一篇的比較全面的 RxJava2 方法總結》
- 《RxJava2 系列 (2):背壓和Flowable》
- 《RxJava2 系列 (3):使用 Subject》
- 《Android 消息機制:Handler、MessageQueue 和 Looper》
你可以通過以上的文章來了解這部分的內容。在本篇文章中,我們主要來梳理下另外兩個多線程相關的 API,HandlerThread 和 IntentService。
1、異步消息隊列:HandlerThread
如果你之前還沒有了解過 Handler 的實現(xiàn)的話,那么最好通過我們上面的那篇文章 《Android 消息機制:Handler、MessageQueue 和 Looper》 了解一下。因為 HandlerThread 就是通過封裝一個 Looper 來實現(xiàn)的。
1.1 HandlerThread 的使用
HandlerThread 繼承自線程類 Thread,內部又維護了一個 Looper,Looper 內又維護了一個消息隊列。所以,我們可以使用 HandlerThread 來創(chuàng)建一個異步的線程,然后不斷向該線程發(fā)送任務。這些任務會被封裝成消息放進 HandlerThread 的消息隊列中被執(zhí)行。所以,我們可以用 HandlerThread 來創(chuàng)建異步的消息隊列。
在使用 HandlerThread 的時候有兩個需要注意的地方:
- 因為 HandlerThread 內部的 Looper 的初始化和開啟循環(huán)的過程都在
run()方法中執(zhí)行,所以,在使用 HandlerThread 之前,你必須調用它的 start() 方法。 - 因為 HandlerThread 的
run()方法使用 Looper 開啟一個了無限循環(huán),所以,當不再使用它的時候,應該調用它的quitSafely()或quit()方法來結束該循環(huán)。
在使用 HandlerThread 的時候只需要創(chuàng)建一個它的實例,然后使用它的 Looper 來創(chuàng)建 Handler 實例,并通過該 Handler 發(fā)送消息來將任務添加到隊列中。下面是一個使用示例:
myHandlerThread = new HandlerThread("MyHandlerThread");
myHandlerThread.start();
handler = new Handler( myHandlerThread.getLooper() ){
@Override
public void handleMessage(Message msg) {
// ... do something
}
};
handler.sendEmptyMessage(1);
這里我們創(chuàng)建了 HandlerThread 實例之后用它來創(chuàng)建 Handler 然后通過 Handler 把任務加入到消息隊列中進行執(zhí)行。
顯然,使用 HandlerThread 可以很輕松地實現(xiàn)一個消息隊列。你只需要在創(chuàng)建了 Handler 之后向它發(fā)送消息,然后所有的任務將被加入到隊列中執(zhí)行。當然,它也有缺點。因為所有的任務將會被按順序執(zhí)行,所以一旦隊列中有某個任務執(zhí)行時間過長,那么就會導致后續(xù)的任務都會被延遲處理。
1.2 HandlerThread 源碼解析
下面是該 API 的源碼,實現(xiàn)也比較簡單,我們直接通過注釋來對主要部分進行說明:
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
protected void onLooperPrepared() { }
// 在這個方法開啟了 Looper 循環(huán),因為是一個無限循環(huán),所以不適用的時候應該將其停止
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
// 獲取該 HandlerThread 對應的 Looper
public Looper getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) { }
}
}
return mLooper;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
// ... 無關代碼
}
上面的代碼比較簡單明了,在 run() 方法中初始化 Looper 并執(zhí)行。如果 Looper 還沒有被創(chuàng)建,那么當調用 getLooper() 方法獲取 Looper 的時候會讓線程阻塞。當 Looper 創(chuàng)建完畢之后會喚醒所有阻塞的線程繼續(xù)執(zhí)行。另外,就是兩個停止 Looper 的方法。它們基本上就是對 Looper 進行了一層封裝。
2、IntentService
2.1 使用 IntentService
IntentService 繼承自 Serivce,因此它比普通的多線程任務優(yōu)先級要高。這使得它相比于普通的異步任務不容易被系統(tǒng) kill 掉。它內部也是通過一個 Looper 來實現(xiàn)的,所以也是一種消息隊列。在研究它的源碼之前,我們先來看一下它的使用。
IntentService 的使用是比較簡單的,只需要:1).繼承它并實現(xiàn)其中的 onHandleIntent() 方法;2). 將 IntentService 注冊到 manifest 中;3). 像開啟一個普通的服務那樣開啟一個 IntentService 即可。下面是該類的一個使用示例:
public class FileRecognizeTask extends IntentService {
public static void start(Context context) {
Intent intent = new Intent(context, FileRecognizeTask.class);
context.startService(intent);
}
public FileRecognizeTask() {
super("FileRecognizeTask");
}
@Override
protected void onHandleIntent(@androidx.annotation.Nullable @Nullable Intent intent) {
// 你的需要異步執(zhí)行的業(yè)務邏輯
}
}
OK,介紹完了 IntentService 的使用,我們再來分析一下它的源碼。
2.2 IntentService 源碼分析
實現(xiàn) IntentService 的時候使用到了我們上面分析過的 HandlerThread. 首先,在 onCreate() 回調方法中創(chuàng)建了一個 HandlerThread,然后使用它的 Looper 創(chuàng)建了一個 ServiceHandler:
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
ServiceHandler 是 IntentSerice 的內部類,其定義如下:
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
ServiceHandler 用來執(zhí)行被添加到隊列中的消息。它會回調 IntentService 中的 onHandleIntent() 方法,也就是我們實現(xiàn)業(yè)務邏輯的方法。當消息執(zhí)行完畢之后,會調用 Service 的 stopSelf(int) 方法來嘗試停止服務。注意這里調用的是 stopSelf(int) 而不是 stopSelf()。它們之間的區(qū)別是,當還存在沒有完成的任務的時候 stopSelf(int) 不會立即停止服務,而 stopSelf() 方法會立即停止服務。
IntentSerivce 的 onCreate() 方法會在第一次啟動的時候被調用,來創(chuàng)建服務。而 onStartCommond() 方法會在每次啟動的時候被調用。下面是該方法的定義。
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
onStartCommand() 內部調用了 onStart() 來處理請求。在 onStart() 方法中會通過 mServiceHandler 創(chuàng)建一個消息,并將該消息發(fā)送給 mServiceHandler. 該消息會在被 mServiceHandler 放進消息隊列中排隊,并在合適的時機被執(zhí)行。
因此,我們可以總結一下 IntentService 的工作過程:首先,當我們第一次啟動 IntentService 的時候會初始化一個 Looper 和 Handler;然后調用它的 onStartCommond() 方法,把請求包裝成消息之后發(fā)送到消息隊列中等待執(zhí)行;當消息被 Handler 處理的時候會回調 IntentService 的 onHandleIntent() 方法來執(zhí)行。此時,如果又有一個任務需要執(zhí)行,那么 IntentService 的 onStartCommond() 方法會再次被執(zhí)行并把請求封裝之后放入隊列中。當隊列中的所有的消息都執(zhí)行完畢,并且沒有新加入的請求,那么此時服務就會自動停止,否則服務還會繼續(xù)在后臺執(zhí)行。
這里,同樣也應該注意下,IntentService 中的任務是按照被添加的順序來執(zhí)行的。
總結
以上就是我們對 IntentService 和 HandlerThread 的分析。它們都是使用了 Handler 來實現(xiàn),所以搞懂它們的前提是搞懂 Handler。關于 Handler,還是推薦一下筆者的另一篇文章 《Android 消息機制:Handler、MessageQueue 和 Looper》。