android Handler消息流程梳理

消息機制概述

Android 系統(tǒng)在設計的初期就已經(jīng)考慮到了 UI 的更新問題呐能,由于 Android 中的 View 是線程不安全的泉褐,然而程序中異步處理任務結束后更新 UI 元素也是必須的租冠。這就造成了一個矛盾掸犬,最簡單的解決方法肯定是給 View 加同步鎖使其變成線程安全的跟匆。這樣做不是不可以甜害,只是會有兩點壞處:

1 加鎖會有導致效率底下

2 由于可以在多個地方更新 UI,開發(fā)就必須很小心操作卑硫,開發(fā)起來就很麻煩徒恋,一不小心就出錯了。

基于以上兩個缺點欢伏,這種方式被拋棄入挣。于是,設置一個線程專門處理 UI控件的更新硝拧,如果其他線程也需要對 UI 進行更新径筏,不好意思,您把您想做的告訴那個專門處理 UI 線程的家伙河爹,讓它幫你做匠璧。大家各有各的任務,井水不犯河水咸这,各司其職夷恍,效率才會高,

那么您也看出來了媳维,消息機制其實可以很簡單的用一句話概括酿雪,就是:其他線程通過給特定線程發(fā)送消息,將某項專職的工作侄刽,交給這個特定的線程去做指黎。比如說其他線程都把處理 UI 顯示的工作通過發(fā)送消息交給 UI 線程去做。?

消息機制相關類

消息主要設計到下面幾個類:

Handler:這是消息的發(fā)出的地方州丹,也是消息處理的地方醋安。

Looper:這是檢測消息的地方。

MessageQueue: 這是存放消息的地方墓毒,Handler 把消息發(fā)到了這里吓揪,Looper 從這里取出消息交給 Handler 進行處理

Message:嗚嗚嗚…他們發(fā)的是我,處理的也是我所计。

Thread:我在這里專門指代的是柠辞,處理消息的線程。消息的發(fā)送是在別的線程主胧。

源碼跟蹤--梳理消息發(fā)送接收過程

咱們先來走一個在子線程想要更新UI的流程:

1?在主線程新建一個 Handler 對象叭首,在構造方法中傳入一個實現(xiàn) Handler.Callback 接口的匿名類的對象习勤,實現(xiàn)接口中的 handleMessage 方法

2?在非 UI 線程使用 Handler 的 sendMessage 或者 post 方法發(fā)送一個消息

3?然后 handleMessage 方法會在不久的將來馬上執(zhí)行,實現(xiàn)更新 UI 的操作焙格。

關于類Handler:

Handler 擁有 Looper 的引用图毕,通過得到 Looper 對象獲得 Looper 中保存的 MessageQueue 對象

Handler 擁有 MessageQueue 的引用,使 Handler 得以擁有發(fā)送消息(將 Message 放入 MessageQueue )的能力

Handler 擁有 Handler.Callback 的引用眷唉,使得 Handler 可以方便的進行消息的處理吴旋。

根據(jù)上面的1 2 3 步,我們跟進源碼看看:

1 創(chuàng)建handler

handler構造方法源碼

在handler中獲取了mLooper厢破,mQueue對象,主要看mLooper是怎么獲取的治拿,Looper.myLooper();再跟進這個方法:

Looper類

可以看到是由ThreadLocal維護的摩泪,我們知道ThreadLocal可以保存對應線程的變量,那么必定保存了當前線程的Looper劫谅。我們查找ThreadLocal.set()方法:

Looper類方法

可以看到是在調用Looper.prepare()時設置的见坑,在主線程中是誰調用Looper.prepare()的呢?沒錯捏检,就是ActivityThread(主線程)荞驴,在創(chuàng)建主線程的main方法里調用:

ActivityThread中的main方法

那么就可以確定,上面ThreadLocal存儲的Looper就是主線程的Looper贯城。mQueue自然也是主線程的Looper的變量熊楼。然后就看發(fā)消息了,看看 Handler.sendMessage 干了啥,

handler類發(fā)送消息

可以看到能犯,Handler類中發(fā)送消息最后調用了MessageQueue的enqueueMessage()方法鲫骗,并且把msg.target設置成了handler本身,這在之后分析中用到踩晶,繼續(xù)跟進:

MessageQueue類方法

到這里执泰,我們發(fā)現(xiàn)handler已經(jīng)成功法一個消息放到了主線程的MessageQueue中了,接下來就是取消息操作了渡蜻。只要主線程中調用了Looper.loop()方法术吝,那就啟動了一個死循環(huán),會從MessageQueue中不停的取消息(無消息就阻塞)茸苇。

Looper的loop方法

可以看到排苍,loop()方法開啟了一個死循環(huán),不斷從MessageQueue取消息税弃,并調用msg.target(Handler)去調用dispatchMessage(msg)方法纪岁。那就是調用了handler的dispatchMessage(msg)方法

handler類方法

這里分三種情況,

? ? * 如果Message中callback對象不為空(這是調用handler.post(Runnable)方法發(fā)送的消息)则果,就調用callback的run方法

? ? * 否則如果創(chuàng)建Handler的時候如果設置了Callback就調用創(chuàng)建時候的傳入的實現(xiàn)Handler.Callback接口的類的對象的handleMessage方法幔翰,看這就是回調方法被調用的地方漩氨。

? ? * 再如果沒有mCallback對象,就調用自身的handleMessage方法遗增,為了Handler的子類復寫了該方法的時候叫惊,方便調用,如做修,IntentService里的ServiceHandler就是繼承自Handler的霍狰,并且重寫了handleMessage方法。

我們創(chuàng)建handler時實現(xiàn)了Handler.Callback接口饰及,所以就跳到一開始創(chuàng)建handler的地方處理消息啦蔗坯。

小結

ok,再整理一下思路:1 在主線程創(chuàng)建handler實現(xiàn)Handler.Callback接口燎含,主線程一運行就存在Loop和MessageQueue宾濒。2 其他線程通過主線程的該handler發(fā)送msg,發(fā)送到了主線程的MessageQueue屏箍。3 主線程的Looper從MessageQueue循環(huán)取消息绘梦,取到該消息就調用msg.target(handler).dispatchMessage(msg),也就跟著調用了handler的handleMessage()。

另外赴魁,如果非主線程要創(chuàng)建handler對象卸奉,必須要調用Looper.prepare()創(chuàng)建一個Looper和Looper.loop()開啟消息循環(huán)。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末颖御,一起剝皮案震驚了整個濱河市榄棵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌郎嫁,老刑警劉巖秉继,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異泽铛,居然都是意外死亡尚辑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門盔腔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來杠茬,“玉大人,你說我怎么就攤上這事弛随∑昂恚” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵舀透,是天一觀的道長栓票。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么走贪? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任佛猛,我火速辦了婚禮,結果婚禮上坠狡,老公的妹妹穿的比我還像新娘继找。我一直安慰自己,他們只是感情好逃沿,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布婴渡。 她就那樣靜靜地躺著,像睡著了一般凯亮。 火紅的嫁衣襯著肌膚如雪边臼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天假消,我揣著相機與錄音硼瓣,去河邊找鬼。 笑死置谦,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的亿傅。 我是一名探鬼主播媒峡,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼葵擎!你這毒婦竟也來了谅阿?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤酬滤,失蹤者是張志新(化名)和其女友劉穎签餐,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盯串,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡氯檐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了体捏。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冠摄。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖几缭,靈堂內(nèi)的尸體忽然破棺而出河泳,到底是詐尸還是另有隱情,我是刑警寧澤年栓,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布拆挥,位于F島的核電站,受9級特大地震影響某抓,放射性物質發(fā)生泄漏纸兔。R本人自食惡果不足惜惰瓜,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望食拜。 院中可真熱鬧鸵熟,春花似錦、人聲如沸负甸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呻待。三九已至打月,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蚕捉,已是汗流浹背奏篙。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留迫淹,地道東北人秘通。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像敛熬,于是被迫代替她去往敵國和親肺稀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

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