by hzwusibo? 20190504
handler的原理驻啤, loop怎么與handler進(jìn)行綁定https://blog.csdn.net/lqb3732842/article/details/54947159handler獲取當(dāng)前線程中的looper對(duì)象狭莱,looper用來從存放Message的MessageQueue中取出Message姨裸,再有handler進(jìn)行Message的分發(fā)與處理盗飒。
https://blog.csdn.net/lmj623565791/article/details/38377229Handler的創(chuàng)建流程
1、首先Looper.prepare()在本線程中保存一個(gè)Looper實(shí)例,然后該實(shí)例中保存一個(gè)MessageQueue對(duì)象喝峦;因?yàn)長ooper.prepare()在一個(gè)線程中只能調(diào)用一次饵撑,所以MessageQueue在一個(gè)線程中只會(huì)存在一個(gè)剑梳。
2唆貌、Looper.loop()會(huì)讓當(dāng)前線程進(jìn)入一個(gè)無限循環(huán),不端從MessageQueue的實(shí)例中讀取消息垢乙,然后回調(diào)msg.target.dispatchMessage(msg)方法锨咙。
3、Handler的構(gòu)造方法追逮,會(huì)首先得到當(dāng)前線程中保存的Looper實(shí)例酪刀,進(jìn)而與Looper實(shí)例中的MessageQueue想關(guān)聯(lián)。
4羊壹、Handler的sendMessage方法蓖宦,會(huì)給msg的target賦值為handler自身,然后加入MessageQueue中油猫。
5稠茂、在構(gòu)造Handler實(shí)例時(shí),我們會(huì)重寫handleMessage方法情妖,也就是msg.target.dispatchMessage(msg)最終調(diào)用的方法睬关。
那么在Activity中,我們并沒有顯示的調(diào)用Looper.prepare()和Looper.loop()方法, 為啥Handler可以成功創(chuàng)建呢毡证?
因?yàn)樵贏ctivity的啟動(dòng)代碼中电爹,已經(jīng)在當(dāng)前UI線程調(diào)用了Looper.prepare()和Looper.loop()方法。
loop自循環(huán)為什么不會(huì)阻塞
https://blog.csdn.net/u013435893/article/details/50903082
Android是事件驅(qū)動(dòng)料睛,Looper內(nèi)部是一個(gè)while死循華丐箩,只有程序退出后循環(huán)才會(huì)停止,如果Looper使用中死掉了恤煞,任何事件都不會(huì)有反應(yīng)了屎勘。事件只會(huì)阻塞Looper,而Looper不會(huì)阻塞事件居扒。
ActivityThread 有個(gè) getHandler 方法概漱,得到這個(gè) handler 就可以發(fā)送消息,然后 loop 里就分發(fā)消息喜喂,然后就發(fā)給 handler, 然后就執(zhí)行到 H(Handler )里的對(duì)應(yīng)代碼瓤摧。所以這些代碼就不會(huì)卡死~,有消息過來就能執(zhí)行玉吁。舉個(gè)例子照弥,在 ActivityThread 里的內(nèi)部類 ApplicationThread 中就有很多 sendMessage 的方法。
簡單的來說:
ActivityThread的main方法主要就是做消息循環(huán)进副,一旦退出消息循環(huán)产喉,那么你的程序也就可以退出了。
從消息隊(duì)列中取消息可能會(huì)阻塞,取到消息會(huì)做出相應(yīng)的處理曾沈。如果某個(gè)消息處理時(shí)間過長这嚣,就可能會(huì)影響UI線程的刷新速率,造成卡頓的現(xiàn)象塞俱。
主要原因有2個(gè)
1姐帚、epoll模型 當(dāng)沒有消息的時(shí)候會(huì)epoll.wait,等待句柄寫的時(shí)候再喚醒障涯,? 主線程大多數(shù)時(shí)候都是處于休眠狀態(tài)罐旗,并不會(huì)消耗大量CPU資源。
2唯蝶、所有的ui操作都通過handler來發(fā)消息操作九秀。 比如屏幕刷新16ms一個(gè)消息,你的各種點(diǎn)擊事件粘我,所以就會(huì)有句柄寫操作鼓蜒,喚醒上文的wait操作,所以不會(huì)被卡死了征字。
主線程的死循環(huán)一直運(yùn)行是不是特別消耗CPU資源呢都弹? 這里涉及到Linux pipe/epoll機(jī)制,簡單說就是在主線程的MessageQueue沒有消息時(shí)匙姜,便阻塞在loop的queue.next()中的nativePollOnce()方法畅厢,此時(shí)主線程會(huì)釋放CPU資源進(jìn)入休眠狀態(tài),直到下個(gè)消息到達(dá)或者有事務(wù)發(fā)生氮昧,通過往pipe管道寫端寫入數(shù)據(jù)來喚醒主線程工作框杜。這里采用的epoll機(jī)制,是一種IO多路復(fù)用機(jī)制袖肥,可以同時(shí)監(jiān)控多個(gè)描述符咪辱,當(dāng)某個(gè)描述符就緒(讀或?qū)懢途w),則立刻通知相應(yīng)程序進(jìn)行讀或?qū)懖僮髡焉欤举|(zhì)同步I/O梧乘,即讀寫是阻塞的澎迎。 所以說庐杨,主線程大多數(shù)時(shí)候都是處于休眠狀態(tài),并不會(huì)消耗大量CPU資源夹供。
https://www.zhihu.com/question/34652589
子線程和子線程之間的通信