類似Binder機制,MessageQueue、Looper也有底層的C++實作,涉及檔案管道和驅動等。
以下僅從Java層的Looper、Handler和MessageQueue等相關類型的源碼來分析線程消息處理的機制。
Looper用來建立和啟動消息隊列。
Looper對象和線程綁定是通過ThreadLocal實作的。
它提供了各種getter友善擷取線程關聯的MessageQueue和Looper對象。
線程通過執行Looper.prepare()來建立關聯的MessageQueue。
主線程則調用prepareMainLooper()來建立主線程關聯的Looper,友善其它線程向主線程發消息。
它建立了Looper對象,以ThreadLocal存儲它,是以和目前線程綁定。
構造函數中建立了消息隊列:
nativeInit()調用C++代碼建立底層的C++MessageQueue對象。
有了MessageQueue對象以後,接着需要開啟消息循環,使用關聯的Handler來發送、處理消息了。
MessageQueue有點像一個阻塞隊列,它提供MessageQueue.next()用來從隊列中取出一個Message對象。
若沒有消息則調用會阻塞。
Looper.loop()用來開啟對MessageQueue的取消息操作的無限循環。
可以看到,loop()的操作就是無限從queue中調用next()擷取一個新Message對象,然後執行dispatchMessage來處理它。
nativePollOnce()用來檢查隊列中是否有新的消息。
參數nextPollTimeoutMillis表示在暫無消息時此次檢查過程需要休眠的時間:
等于-1:表示無限等待,直到被其它線程喚醒。
等于 0:繼續循環檢查隊列。
大于 0:以nextPollTimeoutMillis的毫米數等待。
使用for (;😉 無限循環檢查是否有消息,直到傳回一個Message對象。
若目前MessageQueue正在退出,則傳回null作為辨別。
每次調用next()時,第一次檢查如果發現沒有要出來的消息,就一次性調用所有在注冊了的IdleHandler回調對象。
MessageQueue和Looper對象都是和某個線程關聯的。
向一個線程發送消息,通過和它綁定的一個Handler對象進行。
執行建立Handler對象的的線程,Handler對象和此線程綁定。
Handler對象的構造函數中,将目前線程關聯的Looper和MessageQueue儲存到其字段中。
每個發送到線程關聯的MessageQueue中的Message對象,主要字段有:
long when字段表示消息預期被處理的時間;
int what表示消息的動作;
Object obj可以攜帶額外的資料。
發送消息的一般形式為:
若不指定when那麼它為目前時間,之後被Looper取出後立即執行;
sendMessage()中将<code>Handler Message.target</code>設定為自身,最執行Handler綁定的隊列的MessageQueue.enqueue()方法。
字段<code>Message Message.next</code>用來指向Message連結清單中的下一個對象。
MessageQueue.mMessages字段指向了它擁有的消息連結清單的頭結點。
mMessages中的消息根據其when的時間排列,時間近的在前面。
enqueueMessage()在添加消息時将它放到mMessages的合适的位置。
mBlocked記錄目前隊列是否處于休眠?
在next()時若最近要處理的消息的when還未到或隊列空時,則在檢查隊列是否空時會主動休眠一段時間。
若新的Message被添加到連結清單頭,且它的when時間到了,那麼就喚醒Looper繼續執行next(),擷取此Message然後處理它。
在Looper.loop()中,每當擷取新的消息後:
target就是發送Message的Hander。
Hander發送消息到其綁定的MessageQueue中。
可見,相關的Looper、MessageQueue、Handler都是和同一個線程關聯的。
從next()的執行在Looper.loop()的循環中進行可知:
Hander.dispatchMessage()的調用就是在Looper關聯的線程中進行。
上面的Message.callback是一個Runnable。
Handler.mCallback是建立它時指定的一個回調對象。
handleMessage()就是子類重寫處理自定義消息的地方。
Looper.loop()執行後,線程“阻塞”,不斷從關聯的MessageQueue中取出消息并處理。
其它線程或在處理某個消息的邏輯中,可以調用Looper.quit()退出目前線程的消息循環。
它執行了MessageQueue.quit()。
這裡設定mQuitting為true。
之後下次調用next()時,傳回null告知Looper.loop()退出循環。
線程的消息循環結束。
(本文使用Atom編寫)