HandlerThread繼承自Thread,該類實現了一個帶有Looper的線程,ThreadHandler中的Looper可以被用於創建一個Handler,這樣可以通過在線程中處理handler中的消息隊列;
當然,HandlerThread的實例必須調用start()方法纔可以讓處理Handler發送的消息,也就是說HandlerThread必須是運行狀態的。
源碼分析
在HandlerThread類中,核心代碼就是在run()方法中創建一個Looper對象。這樣就可以通過handler在子線程中處理消息。
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;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* 在looper啓動之前,可用於初始化一些設置
*/
protected void onLooperPrepared() {
}
/**
* 在線程中創建Looper
*/
@Override
public void run() {
mTid = Process.myTid();
// 1、創建Looper,該looper對象實際被存儲在ThreadLocal對象中
Looper.prepare();
synchronized (this) {
// 2、獲取Looper對象,通過ThreadLocal.get()獲取Looper對象
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
// 3、啓動looper消息循環,在消息隊列中獲取消息,該方法是一個阻塞的方法
Looper.loop();
mTid = -1;
}
/**
* 獲取該線程中的Looper對象
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// 當looper被創建後該方法才返回looper對象
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
/**
* 該方法可以返回一個帶有該Looper的Handler的對象,但是該方法被隱藏
*/
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
/**
* 退出handlerThread的looper循環
*
* 通過該方法退出looper循環,將會移除消息隊列中的所有未處理消息
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* 退出handlerThread的looper循環
*
* 通過該方法退出looper循環,將會清楚所有pending的消息,但是對於已經存在於消息隊列中的消息,handler將會繼續處理完成後纔會退出循環。
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* 返回線程id
*/
public int getThreadId() {
return mTid;
}
}
通過上面的代碼我們可以知道,一旦HandlerThread調用start()方法啓動後,Looper對象會一直阻塞等待處理消息隊列中的消息,直到你線程調用quit()或quitSafely()方法,looper循環器纔會停止運行,整個線程纔會停止。
HandlerThread使用場景
通常情況下,都是通過HandlerThread在子線程中執行耗時的操作。同時,因爲在HandlerThread中是通過Looper維護的消息隊列,所以線程在處理任務時時同步的,所以就不需要考慮併發的問題。
代碼示例:
HandlerThread handlerThread = new HandlerThread("WorkThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 這裏可以執行耗時操作,因爲在子線程中
}
};
IntentService
在android源碼中,有一個IntentService的服務類,該類繼承自Service,主要功能就是讓Service在子線程中處理任務,在該類中就是通過HandlerThread實現的。
關於IntentService的介紹,請看 Android IntentService源碼分析
Handler、Thread和HandlerTrhead的關係
一句簡單的話總結這三者的關係就是:
HandlerThread就是一個在Thread中實現handler的機制的一個具體實現。
在這裏明確一個概念,如果想在子線程中創建Handler,那麼必須在handler初始化前爲該線程創建一個Looper對象,否則會拋出一個運行時異常:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at com.zhangke.componentdemo.MainActivity$1.run(MainActivity.java:30)
通常情況下,我們通過下面的代碼爲線程創建Looper:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
關於HandlerThread的介紹就到這裏了。