首先,他們仨是啥?先簡單總結(jié)一下:
1.Looper?
負(fù)責(zé)在所給定線程里run起一個消息循環(huán),往簡單說它就弄了個死循環(huán),不停在message queue里取消息,有消息就處理消息,沒消息就阻塞
這一切是在Loop.loop()實現(xiàn)的,注意,它是這個類的靜態(tài)方法,簡單看一下這個方法的實現(xiàn),我摘取了重要的幾行:
public static Looper myLooper() {
return sThreadLocal.get();//ThreadLocal類,對不同線程不同實例的類,這里對ThreadLocal類的應(yīng)用也是Looper設(shè)計的精髓所在
}
public static void loop() {
final Looper me = myLooper();//獲取當(dāng)前線程的Looper對象
final MessageQueue queue = me.mQueue;
for (;;) {//死循環(huán)
Message msg = queue.next(); // might block阻塞在這里面實現(xiàn)
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);//target就是handler
msg.recycleUnchecked();//回收Message對象,將屬性歸零,將此message對象作為鏈表頭
}
}
另一個重要的static方法,Looper.prepare(),其實就是為當(dāng)前線程創(chuàng)建一個Looper對象
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
2.Message
本質(zhì)上是個鏈表,next對象指向message池中的第一個可用message,至于為啥要節(jié)約使用message對象,要弄個緩存池我沒理解
其中MessageQueue被Looper引用,當(dāng)next方法被調(diào)用時,使用nativePollOnce實現(xiàn)無消息時的阻塞
3.Handler
起到分發(fā)和處理的作用,怎么知道哪個message給哪個handler處理呢?message里面的target屬性,就是指向處理者Handler。其比較重要的幾個方法:
A.構(gòu)造new Handler()會獲取當(dāng)前線程所在looper對象,那么就有個要求啦,必須是一個prepare過的Looper,因為如果不prepare過,那當(dāng)前線程的looper對象是沒有建立的,這點對于主線程來說,在ActivityThread中早就調(diào)用過Looper.prepareMainThread(),因此主線程可以隨便new handler不會報錯,但是在其他線程就不能這么任性了。
B.sendMessage
其實就是把message放到message queue里面
C.obtainMessage
調(diào)用了Message.obtain()方法,新建或重用一個message對象
D.dispatchMessage & handleMessage
Looper的loop方法中調(diào)用dispatchMessage
一般都會重寫handleMessage方法來處理收到的message,如果message自帶callback那就用message自己的callback
其次,為啥會有經(jīng)典的內(nèi)存泄漏問題呢?
如果我們在Activity里面寫個子類MyHandler extends Handler,這樣呢就會遇到一個經(jīng)典的內(nèi)存泄漏問題啦
因為java的內(nèi)部類會持有對外部類的引用,而message對象的target又持有handler的引用,一旦我們發(fā)送一個延遲處理的消息,就會導(dǎo)致關(guān)閉Activity的時候無法回收Activity對象,從而造成泄漏啦。處理的方法,要么就寫成一個靜態(tài)內(nèi)部類,讓handler不要引用Activity,要么就在activity的onDestroy()方法里調(diào)用在activity的onDestroy()方法里調(diào)用handler.removeCallbacksAndMessages(null);把message神馬的都清空,就沒事了
再次,HandlerThread是個什么鬼?
其實它很簡單,它從源碼上看,和Handler沒啥關(guān)系,就是一個帶Looper的Thread,就這么簡單,那為啥叫HandlerThread呢?因為Handler要用它的Looper啊,就這么簡單的關(guān)系。
它能干點啥呢?排隊嘛,因為message是一個個的處理的,所以這個非常適合在work thread中需要一個個依序排隊處理請求的情況。