? ? ? ?怕是要將Android面試常見(jiàn)的問(wèn)題講個(gè)遍雁仲。今天來(lái)分析分析Android 消息運(yùn)行機(jī)制沸久。
? ? ? ? Android 的消息運(yùn)行機(jī)制主要是指Handler的運(yùn)行機(jī)制炼幔。在日常開(kāi)發(fā)中淤井,Handler常用于更新UI等操作聊闯。那么為什么不可以在子線(xiàn)程中更新UI工猜?其實(shí)可以這樣理解,Android的UI是線(xiàn)程不安全菱蔬,如果我們多線(xiàn)程并發(fā)的更新UI篷帅,那么就會(huì)使得UI控件的值處于不可確定的狀態(tài),此時(shí)就會(huì)導(dǎo)致UI顯示結(jié)果并不是自己所預(yù)想的拴泌,如果我們對(duì)UI進(jìn)行加鎖呢魏身,我認(rèn)為加鎖首先會(huì)導(dǎo)致阻塞線(xiàn)程,降低UI的更新效率弛针,同時(shí)叠骑,我們加鎖后,可想此時(shí)UI的邏輯會(huì)變得很復(fù)雜削茁,此時(shí)我們就可以使用Handler來(lái)處理宙枷,會(huì)顯得更方便掉房。 線(xiàn)程是默認(rèn)沒(méi)有Looper的,而主線(xiàn)程再被創(chuàng)建時(shí)候就會(huì)初始化Looper慰丛,這就是主線(xiàn)程可以使用Handler原因卓囚。? ?
????????Handler的運(yùn)行則由Looper和MessageQueue來(lái)輔助完成。在我們創(chuàng)建Handler時(shí)候诅病,就會(huì)創(chuàng)建Looper對(duì)象和消息隊(duì)列MessageQueue及Handler哪亿,此時(shí)Handler,looper,MessageQueue就組成了消息的運(yùn)行機(jī)制。
? ? ? ? Handler整個(gè)的運(yùn)行是:Handler發(fā)送一個(gè)消息時(shí)贤笆,將消息放入MessageQueue的消息隊(duì)列中蝇棉,Looper發(fā)現(xiàn)消息時(shí)候,則會(huì)處理這條消息芥永,然后Handler的handleMessage的方法就會(huì)被調(diào)用篡殷。那么首先就開(kāi)始研究Looper:
? ? ? ??談到Looper時(shí),那么就會(huì)提到ThreadLocal,ThreadLocal 是什么呢埋涧?它是一個(gè)線(xiàn)程內(nèi)部的數(shù)據(jù)儲(chǔ)存類(lèi)板辽, Handler創(chuàng)建時(shí)候會(huì)采用當(dāng)前線(xiàn)程的Looper來(lái)構(gòu)建消息循環(huán)系統(tǒng),而獲取當(dāng)前的Lopper則通過(guò)ThreadLocal棘催,下文源碼可看出劲弦。下面通過(guò)源碼來(lái)分析和研究Looper:
? ? ? ?首先看看Looper的構(gòu)造方法,由下面源碼可以看出醇坝,此時(shí)我們創(chuàng)建Looper對(duì)象的時(shí)候邑跪,同時(shí)也創(chuàng)建了消息隊(duì)列MessageQueue ,并保存當(dāng)前線(xiàn)程的對(duì)象纲仍。
? ? 接下來(lái)就是Looper的初始化 :
? ? ? ?由上可以看出Looper創(chuàng)建是通過(guò)Looper.perpare()和prepareMainLooper()來(lái)創(chuàng)建的呀袱。其中prepareMainLooper從英文的注釋中我們可以看出此方法是給ActivityThread創(chuàng)建Looper使用贸毕,其本質(zhì)也是prepare 郑叠。創(chuàng)建消息隊(duì)列后,那么Looper就開(kāi)始自己的死循環(huán)工作了明棍,分析主要源碼如下圖:
? ? ? ? Looper的loop方法就是一個(gè)死循環(huán)乡革,其中退出這個(gè)死循環(huán)的方法是msg為空的時(shí)候(后面分析)。在msg空上面摊腋,還有一個(gè)方法MessageQueue的next方法沸版,接下來(lái)看看MessageQueue的next方法:
? ? ? ?此時(shí),next里面又是一個(gè)死循環(huán)兴蒸。MessageQueue中有個(gè)阻塞機(jī)制视粮,如上圈圈部分,那么是什么使得阻塞呢橙凳?接下來(lái)看看阻塞的觸發(fā)條件蕾殴,如下圖(接上源碼)笑撞,源碼很簡(jiǎn)單,當(dāng)消息隊(duì)列中沒(méi)有消息時(shí)候钓觉,此時(shí)將nextPollTimeoutMillis設(shè)置為-1茴肥,此時(shí)阻塞再next方法中,直到有消息來(lái)臨的時(shí)候荡灾。
? ? ? ? ? ?那么怎么跳出這個(gè)Looper呢瓤狐。Looper中提供了Quit方法如下,直接調(diào)用quit方法即可跳出當(dāng)前l(fā)ooper批幌,
? ? ? ? ?我們繼續(xù)看看到底是怎么跳出當(dāng)前Looper础锐,進(jìn)一步看看,此時(shí)可以看出荧缘,此時(shí)是將消息制空郁稍,正好對(duì)應(yīng)上面的msg為空的時(shí)候。(怎么處理Handler泄露問(wèn)題就不分析了胜宇,哈哈)
? ? ? ? 那么接下來(lái)耀怜,有消息的時(shí)候消息的分發(fā)處理。如下桐愉,可以看出财破,Handler發(fā)送消息過(guò)程,僅僅是向消息隊(duì)列中插入一條消息从诲,MessageQueue的next 將這條消息返回給Looper左痢,Looper接到消息開(kāi)始處理,最終交給Handler處理系洛,然后觸發(fā)Handler的 dispatchMessage俊性,源碼很簡(jiǎn)單,我們可以看出消息的處理了描扯。
? ? ? ? 以上Android消息運(yùn)行機(jī)制就講完了定页,畫(huà)個(gè)圖,算了绽诚,畫(huà)圖不是我所愛(ài)典徊。
? ? ? ?由于水平有限,如有不對(duì)恩够,歡迎指正卒落。