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