Android中Handler機(jī)制原理淺析

對(duì)于我們來(lái)說(shuō)Handler機(jī)制是日常開(kāi)發(fā)中經(jīng)常用到的碳蛋,我們可以使用它輕松實(shí)現(xiàn)線(xiàn)程間的切換和延時(shí)操作龄砰。今天我們就來(lái)分析一下Handler的實(shí)現(xiàn)原理塑径。我們先來(lái)看一下Handler機(jī)制的中重要的四個(gè)類(lèi)和一個(gè)工具葡盗。
Handler 用于消息的發(fā)送和接受消息
Message 消息
MessageQueue 單向綁定的消息列表
Looper 消費(fèi)消息
ThreadLocal 數(shù)據(jù)儲(chǔ)存

一审磁、ThreadLocal

ThreadLocal主要作用是將數(shù)據(jù)綁定當(dāng)線(xiàn)程上酒来,接下來(lái)我們主要是看它的get和set方法卢未。

上面的get方法中會(huì)先獲取當(dāng)前線(xiàn)程,然后以該線(xiàn)程為key去查找對(duì)應(yīng)的Value堰汉,如果Value為null時(shí)會(huì)返回setInitialValue()方法中的值辽社,其實(shí)setInitialValue()方法放回的就是一個(gè)初始值默認(rèn)為null我們可以通過(guò)重寫(xiě)initialValue()方法來(lái)設(shè)置初始值。

set方法就簡(jiǎn)單多了翘鸭,它就是以當(dāng)前的線(xiàn)程為key進(jìn)行數(shù)據(jù)的存儲(chǔ)滴铅。這樣就能把數(shù)據(jù)綁定到線(xiàn)程上了。

二矮固、Message

消息對(duì)象就是一個(gè)數(shù)據(jù)類(lèi)失息。Message的創(chuàng)建方法有兩種,一個(gè)是直接使用new關(guān)鍵字另一個(gè)就是通過(guò)obtain方法進(jìn)行創(chuàng)建了档址。兩個(gè)種方法有什么區(qū)別呢為什么推薦我們使用obtain方法創(chuàng)建Message盹兢。我們分析obtain方法的時(shí)要對(duì)應(yīng)的看一下它的回收方法recycleUnchecked

如果我們直接去看obtain方法的話(huà)可能理解起來(lái)有一定的困難。我們可以先從它的回收方法開(kāi)始分析守伸。我們主要看一下回收方法中同步代碼塊的代碼绎秒,它先判斷sPoolSize是否小于MAX_POOL_SIZE,sPoolSize的初始值為0 MAX的值為50 接下來(lái)就是next = sPool尼摹;next和sPool的類(lèi)型都是Message见芹,sPool是個(gè)靜態(tài)的屬性。他將要回收的message的next賦值為sPool再將Message賦值給靜態(tài)屬性sPool然后sPoolSize++蠢涝,他這是干呢玄呛?其實(shí)sPool是Message內(nèi)部的一個(gè)大小為50的單向緩存列表。執(zhí)行回收方法時(shí)先判斷緩存列表的個(gè)數(shù)和二,如果小于50就將回收的Message添加到列表中徘铝。
知道sPool是一個(gè)緩存列表之后我們?cè)偃シ治鰋btain方法就簡(jiǎn)單了,它就是先去sPool中去取緩存惯吕,沒(méi)有緩存時(shí)就通過(guò)new 關(guān)鍵字來(lái)創(chuàng)建一個(gè)新的返回惕它。
Message中的target屬性我們也要知道,他是用于存儲(chǔ)發(fā)送該消息的handler废登。在handler發(fā)送消息時(shí)進(jìn)行的賦值淹魄。

三、Handler

Handler的作用就是進(jìn)行消息的發(fā)送與接送堡距。

我們先看一下Handler創(chuàng)建過(guò)程中都做了什么甲锡。

標(biāo)注1處就是通過(guò)ThreadLocal獲取當(dāng)前線(xiàn)程綁定的Looper兆蕉。這里有一個(gè)常見(jiàn)的問(wèn)題就是在子線(xiàn)程中為什么不是直接使用Handler,就是因?yàn)樵谧泳€(xiàn)程中創(chuàng)建Handler時(shí)不能獲取子線(xiàn)程對(duì)應(yīng)的Looper從而拋出了異常搔体,那為什么子線(xiàn)程不能直接創(chuàng)建Handler而主線(xiàn)程卻可以呢恨樟?這個(gè)我們?cè)贚ooper那里進(jìn)行分析。標(biāo)注2處就是獲取Looper中的MessageQueue賦值給成員變量mQueue疚俱。接下來(lái)看一下發(fā)送消息的過(guò)程劝术。

handler發(fā)送消息的方法有很多個(gè),但都是在計(jì)算出一個(gè)時(shí)間戳之后去調(diào)用了enqueueMessage方法呆奕。方法中為msg.target賦值為當(dāng)前的handler养晋。最后調(diào)用MessageQueue的enqueueMessage方法將消息添加到消息列表中。以上就是handler發(fā)送消息的過(guò)程梁钾。對(duì)于handler接受消息的過(guò)程我們?cè)贚ooper中進(jìn)行分析绳泉,大致過(guò)程就是Looper拿到消息后調(diào)用通過(guò)message的target獲取對(duì)應(yīng)的handler再調(diào)用handler的dispatchMessage方法回調(diào)我們重寫(xiě)的方法。

四姆泻、Looper

Looper的作用就是循環(huán)的取出MessageQueue中Message并將他們分發(fā)給對(duì)應(yīng)的Handler零酪。
在講Handler的時(shí)候我們說(shuō)到?jīng)]什么主線(xiàn)程中可以取到Looper而子線(xiàn)程中就取不到呢。這是因?yàn)橄到y(tǒng)在ActivityThread的main方法中進(jìn)行了創(chuàng)建拇勃,我們看一下main方法四苇。

在main方法中主要是調(diào)用了Looper的prepareMainLooper方法和loop方法。我們先看一下prepareMainLooper方法

prepareMainLooper方法就是創(chuàng)建了Looper并將該Looper保存到了ThreadLocal中方咆,同時(shí)創(chuàng)建了對(duì)應(yīng)了的MessageQueue月腋。這樣主線(xiàn)程上面就綁定了一個(gè)Looper。那我們我們要想在子線(xiàn)程中使用handler的話(huà)要手動(dòng)調(diào)用Looper.prepare()在子線(xiàn)程中創(chuàng)建一個(gè)Looper瓣赂,然后調(diào)用loop方法開(kāi)啟循環(huán)榆骚。

loop方法比較長(zhǎng)我們主要看四個(gè)地方就可以了,標(biāo)注1 在調(diào)用loop方法后會(huì)開(kāi)啟一個(gè)死循環(huán)煌集。標(biāo)注 2 此處調(diào)用了MessageQueue的next方法來(lái)獲取列表中的消息妓肢,沒(méi)有事消息時(shí)阻塞。標(biāo)注3 獲取到message后通過(guò)它的target屬性獲取對(duì)應(yīng)的handler并調(diào)用dispatchMessage方法苫纤。標(biāo)注4 message處理完成后調(diào)用它的回收方法职恳。

五、MessageQueue

用于存儲(chǔ)消息方面。我們主要看一下它的儲(chǔ)存方法和取出方法。先看他的儲(chǔ)存方法色徘。

它主要是通過(guò)when這個(gè)是延時(shí)時(shí)間來(lái)判斷message添加到mMessage中的位置恭金。mMessage也是一個(gè)單項(xiàng)列表。

next方法比較長(zhǎng)它的主要功能就是循環(huán)的返回列表中的message褂策,沒(méi)有值的時(shí)候通過(guò)native方法就行阻塞横腿。

六颓屑、總結(jié)

我們對(duì)Handler機(jī)制中的各個(gè)部分進(jìn)行了逐一的分析,已經(jīng)大概知道各部分的作用及整個(gè)機(jī)制的運(yùn)作過(guò)程耿焊【镜耄可以用下圖簡(jiǎn)單表示。


該文檔是自己的學(xué)習(xí)記錄如有錯(cuò)誤歡迎指出罗侯。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末器腋,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子钩杰,更是在濱河造成了極大的恐慌纫塌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讲弄,死亡現(xiàn)場(chǎng)離奇詭異措左,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)怎披,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)赏壹,“玉大人昔瞧,你說(shuō)我怎么就攤上這事稍坯』烨桑” “怎么了陨亡?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我燎悍,道長(zhǎng)宏怔,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任玷或,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布椎木。 她就那樣靜靜地躺著畜伐,像睡著了一般悼吱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上遇西,一...
    開(kāi)封第一講書(shū)人閱讀 52,457評(píng)論 1 311
  • 那天馅精,我揣著相機(jī)與錄音硫嘶,去河邊找鬼第队。 笑死家凯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掂之。 我是一名探鬼主播抗俄,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼跟压!你這毒婦竟也來(lái)了胰蝠?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤裆馒,失蹤者是張志新(化名)和其女友劉穎姊氓,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體喷好,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡翔横,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了梗搅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片禾唁。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖无切,靈堂內(nèi)的尸體忽然破棺而出荡短,到底是詐尸還是另有隱情,我是刑警寧澤哆键,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布掘托,位于F島的核電站,受9級(jí)特大地震影響籍嘹,放射性物質(zhì)發(fā)生泄漏闪盔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一辱士、第九天 我趴在偏房一處隱蔽的房頂上張望泪掀。 院中可真熱鬧,春花似錦颂碘、人聲如沸异赫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)塔拳。三九已至鼠证,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間靠抑,已是汗流浹背名惩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留孕荠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓攻谁,卻偏偏與公主長(zhǎng)得像稚伍,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子戚宦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

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