前幾天看到一道面試題:Thread、Handler和HandlerThread有什麼區別?,這個題目有點意思,對於不少人來講,可能對Thread和Handler很熟悉,主要涉及到Android的消息機制(Handler、Message、Looper、MessageQueue),詳見《 從Handler.post(Runnable r)再一次梳理Android的消息機制(以及handler的內存泄露)》面試
可是這個HandlerThread是拿來作什麼的呢?它是Handler仍是Thread?咱們知道Handler是用來異步更新UI的,更詳細的說是用來作線程間的通訊的,更新UI時是子線程與UI主線程之間的通訊。那麼如今咱們要是想子線程與子線程之間的通訊要怎麼作呢?固然說到底也是用Handler+Thread來完成(不推薦,須要本身操做Looper),Google官方很貼心的幫咱們封裝好了一個類,那就是剛纔說到的:HandlerThread。(相似的封裝對於多線程的場景還有AsyncTask)bash
仍是先來看看HandlerThread的使用方法: 首先新建HandlerThread而且執行start()多線程
private HandlerThread mHandlerThread;
......
mHandlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
複製代碼
建立Handler,使用mHandlerThread.getLooper()生成Looper:異步
final Handler handler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
System.out.println("收到消息");
}
};
複製代碼
而後再新建一個子線程來發送消息:ide
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);//模擬耗時操做
handler.sendEmptyMessage(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
複製代碼
最後必定不要忘了在onDestroy釋放,避免內存泄漏:oop
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
}
複製代碼
執行結果很簡單,就是在控制檯打印字符串:收到消息post
整個的使用過程咱們根本不用去關心Handler相關的東西,只須要發送消息,處理消息,Looper相關的東西交給它本身去處理,仍是來看看源碼它是怎麼實現的,先看構造方法:ui
public class HandlerThread extends Thread {}
複製代碼
HandlerThread其實仍是一個線程,它跟普通線程有什麼不一樣?this
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
......
}
複製代碼
答案是多了一個Looper,這個是子線程獨有的Looper,用來作消息的取出和處理。繼續看看HandlerThread這個線程的run方法:spa
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();//生成Looper
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();//空方法,在Looper建立完成後調用,能夠本身重寫邏輯
Looper.loop();//死循環,不斷從MessageQueue中取出消息而且交給Handler處理
mTid = -1;
}
複製代碼
主要就是作了一些Looper的操做,若是咱們本身使用Handler+Thread來實現的話也要進行這個操做,再來看看getLooper()方法:
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
複製代碼
方法很簡單,就是加了個同步鎖,若是已經建立了(isAlive()返回true)可是mLooper爲空的話就繼續等待,直到mLooper建立成功,最後看看quit方法,值得一提的是有兩個:
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;
}
複製代碼
quitSafely是針對在消息隊列中還有消息或者是延遲發送的消息沒有處理的狀況,調用這個方法後都會被中止掉。
HandlerThread的使用方法仍是比較簡單的,可是咱們要明白一點的是:若是一個線程要處理消息,那麼它必須擁有本身的Looper,並非Handler在哪裏建立,就能夠在哪裏處理消息的。
若是不用HandlerThread的話,須要手動去調用Looper.prepare()和Looper.loop()這些方法。