Android異步消息處理機制源碼分析

一获印、概述

Handler 、 Looper 、Message 這三者都與Android異步消息處理線程相關的概念紧唱。那么什么叫異步消息處理線程呢?異步消息處理線程啟動后會進入一個無限的循環(huán)體之中隶校,每循環(huán)一次漏益,從其內(nèi)部的消息隊列中取出一個消息,然后回調(diào)相應的消息處理函數(shù)深胳,執(zhí)行完成一個消息后則繼續(xù)循環(huán)绰疤。若消息隊列為空,線程則會阻塞等待舞终。那么和Handler 轻庆、 Looper 、Message有啥關系敛劝?其實Looper負責的就是創(chuàng)建一個MessageQueue余爆,然后進入一個無限循環(huán)體不斷從該MessageQueue中讀取消息,而消息的創(chuàng)建者就是Handler 夸盟。啥也不說了直接看源碼

二蛾方、源碼分析

1.Looper

對于Looper主要是prepare()和loop()兩個方法。首先看prepare()方法

圖1

sThreadLocal是一個ThreadLocal對象上陕,可以在一個線程中存儲變量桩砰。可以看到释簿,在第91行亚隅,將一個Looper的實例放入了ThreadLocal,并且2-在前面判斷sThreadLocal是否為null庶溶,否則拋出異常煮纵。這也就說明了Looper.prepare()方法不能被調(diào)用兩次,同時也保證了一個線程中只有一個Looper實例渐尿。

再來看Looper的構造方法:

圖2

在構造方法中醉途,創(chuàng)建了一個MessageQueue(消息隊列)。

然后我們來看loop()方法:

圖3
圖4

圖3+圖4是整個的looper方法代碼(代碼一屏截不完所以分兩次截茸┤住)

第124行:

public static Looper myLooper() {

return sThreadLocal.get();

}

方法直接返回了sThreadLocal存儲的Looper實例隘擎,如果me為null則拋出異常,也就是說looper方法必須在prepare方法之后運行凉夯。

第128行:拿到該looper實例中的mQueue(消息隊列)。

135到177行:就進入了我們所說的無限循環(huán)铺坞。

136行:取出一條消息慕购,如果沒有消息則阻塞。

154行:使用調(diào)用? msg.target.dispatchMessage(msg);把消息交給msg的target的dispatchMessage方法去處理休傍。msg的target其實就是handler對象,接下來會進行分析蹲姐。

176行:釋放消息占據(jù)的資源磨取。

Looper主要作用:

1、與當前線程綁定柴墩,保證一個線程只會有一個Looper實例忙厌,同時一個Looper實例也只有一個MessageQueue。

2江咳、loop()方法逢净,不斷從MessageQueue中去取消息,交給消息的target屬性的dispatchMessage去處理歼指。

2.Handler

使用Handler之前爹土,我們都是初始化一個實例,比如用于更新UI線程踩身,我們會在聲明的時候直接初始化胀茵,或者在onCreate中初始化Handler實例。所以我們首先看Handler的構造方法惰赋,看其如何與MessageQueue聯(lián)系上的宰掉,它在子線程中發(fā)送的消息(一般發(fā)送消息都在非UI線程)怎么發(fā)送到MessageQueue中的。

圖5

198行:通過Looper.myLooper()獲取了當前線程保存的Looper實例赁濒,然后在203行又獲取了這個Looper實例中保存的MessageQueue(消息隊列)轨奄,這樣就保證了handler的實例與我們Looper實例中MessageQueue關聯(lián)上了。

然后看我們最常用的sendMessage方法

圖6


圖7


圖8


圖9

sendMessage方法最終調(diào)用了enqueueMessage方法拒炎。

enqueueMessage方法中首先為msg.target賦值為this挪拟,也就印證了上面我們說的msg.target是handler對象。最終會調(diào)用queue的enqueueMessage的方法击你,也就是說handler發(fā)出的消息玉组,最終會保存到消息隊列中去。

現(xiàn)在已經(jīng)很清楚了Looper會調(diào)用prepare()和loop()方法丁侄,在當前執(zhí)行的線程中保存一個Looper實例惯雳,這個實例會保存一個MessageQueue對象,然后當前線程進入一個無限循環(huán)中去鸿摇,不斷從MessageQueue中讀取Handler發(fā)來的消息石景。然后再回調(diào)創(chuàng)建這個消息的handler中的dispathMessage方法,下面我們趕快去看一看這個方法:

圖10


圖11

到此,整個消息機制分析完畢了潮孽,讓我們首先總結(jié)一下

1揪荣、首先Looper.prepare()在本線程中保存一個Looper實例,然后該實例中保存一個MessageQueue對象往史;因為Looper.prepare()在一個線程中只能調(diào)用一次仗颈,所以MessageQueue在一個線程中只會存在一個。

2椎例、Looper.loop()會讓當前線程進入一個無限循環(huán)挨决,不斷從MessageQueue的實例中讀取消息,然后回調(diào)msg.target.dispatchMessage(msg)方法處理粟矿。

3凰棉、Handler的構造方法损拢,會首先得到當前線程中保存的Looper實例陌粹,進而與Looper實例中的MessageQueue相關聯(lián)。

4福压、Handler的sendMessage方法掏秩,會給msg的target賦值為handler自身,然后加入MessageQueue中荆姆。

5蒙幻、在構造Handler實例時,我們會重寫handleMessage方法胆筒,也就是msg.target.dispatchMessage(msg)最終調(diào)用的方法邮破。

三、補充

1.有的人可能會問仆救,在Activity中抒和,我們并沒有顯示的調(diào)用Looper.prepare()和Looper.loop()方法,為啥Handler可以成功創(chuàng)建呢彤蔽,這是因為在Activity的啟動代碼中摧莽,已經(jīng)在當前UI線程調(diào)用了Looper.prepare()和Looper.loop()方法(具體可以查看ActivityThread.java 代碼)。

2.Handler不僅可以更新UI顿痪,你完全可以在一個子線程中去創(chuàng)建一個Handler镊辕,然后使用這個handler實例在任何其他線程中發(fā)送消息,最終處理消息的代碼都會在你創(chuàng)建Handler實例的線程中運行蚁袭。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末征懈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子揩悄,更是在濱河造成了極大的恐慌卖哎,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異棉饶,居然都是意外死亡厦章,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門照藻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來袜啃,“玉大人,你說我怎么就攤上這事幸缕∪悍ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵发乔,是天一觀的道長熟妓。 經(jīng)常有香客問我,道長栏尚,這世上最難降的妖魔是什么起愈? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮译仗,結(jié)果婚禮上抬虽,老公的妹妹穿的比我還像新娘。我一直安慰自己纵菌,他們只是感情好阐污,可當我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著咱圆,像睡著了一般笛辟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上序苏,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天手幢,我揣著相機與錄音,去河邊找鬼杠览。 笑死弯菊,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的踱阿。 我是一名探鬼主播管钳,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼软舌!你這毒婦竟也來了才漆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤佛点,失蹤者是張志新(化名)和其女友劉穎醇滥,沒想到半個月后黎比,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡鸳玩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年阅虫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片不跟。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡颓帝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出窝革,到底是詐尸還是另有隱情购城,我是刑警寧澤,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布虐译,位于F島的核電站瘪板,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏漆诽。R本人自食惡果不足惜侮攀,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拴泌。 院中可真熱鬧魏身,春花似錦、人聲如沸蚪腐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽回季。三九已至,卻和暖如春正林,著一層夾襖步出監(jiān)牢的瞬間泡一,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工觅廓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鼻忠,地道東北人。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓杈绸,卻偏偏與公主長得像帖蔓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子瞳脓,可洞房花燭夜當晚...
    茶點故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內(nèi)容