Android消息機制其實就是Handler险绘、Looper誉碴、MessageQueue三者之間的配合。Handler為入口代咸,負責用戶發(fā)送消息蹬屹;MessageQueue為消息容器慨默,負責管理Android的消息儲存于消費弧腥;Looper為消息輪詢機制,負責從MessageQueue隊列中取出消息虾攻,交給Handler處理。
原理
當Handler建立是需要傳一個Looper(創(chuàng)建的線程已有Looper的情況下不需要傳)奇钞,故Looper為Handler的成員變量漂坏。Handler的主要成員變量有以下這些:
1顶别、mLooper 以上已說明
2、mQueue 消息隊列完慧,其實是實例Looper的成員變量剩失,下面會做說明
3、mCallback 處理消息的回調(diào)鸿染,看下系統(tǒng)對這個類的描述
Callback interface you can use when instantiating a Handler to avoid having to implement your own subclass of Handler.
意思是當你設置此回調(diào)后就不用在你的Hander類中去實現(xiàn)handleMessage的回調(diào)了乞巧,主要用處如圖1
明顯绽媒,當有mCallback 回調(diào)后就不會走handleMessage了
4、mAsynchronous消息類型標志囤热,mAsynchronous為true時表明時異步消息获三,默認為false同步消息疙教,異步消息一般是系統(tǒng)發(fā)送ui刷新指令,當發(fā)送一個同步屏障后限佩,Hander會優(yōu)先處理異步消息,保證了UI消息實時更新
一般使用Handler發(fā)送消息作喘,使用post晕城、postDelay、或者sendMessage暇矫、sendMessageDelayed择吊,實際最終都是調(diào)用sendMessageAtTime——> enqueueMessage(該處主要設置處理消息的Target几睛、設置消息類型mAsynchronous)——> enqueueMessage(將消息插入到消息隊列),如圖2囱持,該邏輯很簡單焕济,當入隊消息先目前消息發(fā)生時,入隊消息會插入到消息頭部掩幢,如果不是的話會根據(jù)入隊消息發(fā)生的時間插入到隊列相應的位置
消息被放入到消息隊列际邻,那何時處理該消息的呢世曾?
實際Looper在創(chuàng)建后谴咸,需要去啟動,調(diào)用loop()方法血巍,開啟消息輪詢處理機制驼唱,如圖3
當輪詢機制打開后玫恳,主要通過MessageQueue的next方法去取消息隊列的中的消息,當有消息需要處理時掀序,調(diào)用msg.target.dispatchMessage(msg)不恭,此時就回到了圖1的方法财饥,那next方法時如何實現(xiàn)的呢?沾瓦?如圖4
該方法是個for的死循環(huán)贯莺,方法根據(jù)當前時間now和消息時間msg.when宁改,當當前時間大于等于改時間,說明該消息需要處理了爹耗,故從隊列中取出該消息進行處理
至此谜喊,整個Handler消息處理機制說完了锅论,總結(jié)如下:
Handler通過發(fā)送消息時根據(jù)其發(fā)生隊列插入到消息隊列MessageQueue里,Looper開啟循環(huán)機制根據(jù)發(fā)生時間去隊列中取出應處理的消息交有目標Handler處理
疑問
1怒坯、Handler為什么會造成內(nèi)存泄漏藻懒?
非靜態(tài)的Handler對象由于持有外部類的對象嬉荆,而Handler被每個Message持有(Message.target),而Message被隊列MessageQueue持有,MessageQueue被Looper持有汪茧,Looper被靜態(tài)變量sThreadLocal持有椅亚,故當消息不能及時消費時會產(chǎn)生內(nèi)存泄漏
2、IdleHandler是什么舱污,什么時候會執(zhí)行呀舔?
IdleHandler時Android一種利用空閑時間處理不重要消息的機制,當用戶通過addIdleHandler設置了該任務時扩灯,任務會被加入到mIdleHandlers
數(shù)組中媚赖,執(zhí)行next方法時,如圖4珠插,當當前時間沒有任何消息需要處理時惧磺,會去執(zhí)行mPendingIdleHandlers也就是mIdleHandlers里面的任務idler.queueIdle()
3捻撑、Android消息同步屏障是什么意思磨隘,如何實現(xiàn)?布讹?
Android為了保證UI的刷新時效琳拭,引入了消息同步屏障,當有優(yōu)先異步消息需要處理時描验,mHandler.getLooper().getQueue().postSyncBarrier()調(diào)用MessageQueue的postSyncBarrier()方法白嘁,所謂同步屏障,實際就是插入一個沒有target的Message膘流。
當loop.next時如圖4絮缅,for循環(huán)會優(yōu)先根據(jù)msg.target為null時,會優(yōu)先去去異步消息進行消費