Handler原理

概述

很多android初學(xué)者對android 中的handler不是很明白斜棚,其實Google參考了Windows的消息處理機(jī)制,

在Android系統(tǒng)中實現(xiàn)了一套類似的消息處理機(jī)制边败。在下面介紹handler機(jī)制前脑蠕,首先得了解以下幾個概念:

####1. Message

 消息皿曲,理解為線程間通訊的數(shù)據(jù)單元摩疑。例如后臺線程在處理數(shù)據(jù)完畢后需要更新UI,則可發(fā)送一條包含更新信息的Message給UI線程鞋怀。

####2. Message Queue

 消息隊列双泪,用來存放通過Handler發(fā)布的消息,按照先進(jìn)先出執(zhí)行密似。

####3. Handler

 Handler是Message的主要處理者焙矛,負(fù)責(zé)將Message添加到消息隊列以及對消息隊列中的Message進(jìn)行處理。

####4. Looper

 循環(huán)器残腌,扮演Message Queue和Handler之間橋梁的角色村斟,循環(huán)取出Message Queue里面的Message贫导,并交付給相應(yīng)的Handler進(jìn)行處理。

####5. 線程

 UI thread 通常就是main thread蟆盹,而Android啟動程序時會替它建立一個Message Queue孩灯。

每一個線程里可含有一個Looper對象以及一個MessageQueue數(shù)據(jù)結(jié)構(gòu)。在你的應(yīng)用程序里逾滥,可以定義Handler的子類別來接收Looper所送出的消息峰档。


image.png

好了,下面是正文~

Handler作用:

因為在Android中寨昙,主線程不建議做耗時的操作讥巡,子線程不建議跟新UI,但是Android開發(fā)舔哪,其實就是搭建好頁面欢顷,將服務(wù)器的數(shù)據(jù)展示到頁面上,所以我網(wǎng)絡(luò)請求使用會非常頻繁捉蚤,而網(wǎng)絡(luò)請求屬于耗時操作吱涉,需要放到子線程完成,但一般情況下也不會通過子線程更新UI外里,需要將請求成功的數(shù)據(jù)發(fā)送到主線程進(jìn)行UI更新,所以一般會使用到handler特石。

Handler執(zhí)行流程:

首先handler作為任務(wù)執(zhí)行者盅蝗,一般創(chuàng)建在主線程,當(dāng)子線程有需要發(fā)送的數(shù)據(jù)姆蘸,通過創(chuàng)建message對象墩莫,使用handler對象將消息發(fā)送到messagequeue,messagequeue遵循了隊列先進(jìn)先出的原則逞敷,當(dāng)主線程的looper循環(huán)消息的時候狂秦,會按照messagequeue隊列的順序循環(huán)消息,并將消息給到任務(wù)執(zhí)行者h(yuǎn)andler去執(zhí)行任務(wù)推捐。

Handler執(zhí)行原理:

Handler創(chuàng)建完成后裂问,內(nèi)部的Looper以及MessageQueue就可以和Handler一起協(xié)同工作,然后通過Hadler的post方法將一個Runnable投遞到Handler內(nèi)部的Looper中去處理牛柒,也可以通過Handler的send方法發(fā)送一個消息堪簿,這個消息會在Looper中做處理。Post最終也是通過send來完成的皮壁。當(dāng)Handler的send方法被調(diào)用時椭更,他會調(diào)用MessageQueue的enqueueMessage方法將這個消息放入消息隊列中,然后Looper發(fā)現(xiàn)有新消息到來時蛾魄,就會處理這個消息虑瀑,最終消息中的Runnable或者Handler的handlerMessage方法就會被調(diào)用湿滓。Looper試運(yùn)行在Handler所在的線程,所以就把業(yè)務(wù)邏輯切換到主線程了

1.ThreadLocal的工作原理

(1)定義:ThreadLocal是線程內(nèi)部的數(shù)據(jù)存儲類舌狗,通過他可以在指定的線程中存儲數(shù)據(jù)叽奥,該數(shù)據(jù)只有在指定線程中可以獲取
(2)使用場景:當(dāng)某些數(shù)據(jù)是以線程為作用域并且不同線程具有不同的數(shù)據(jù)副本的時候另外還可以使用在復(fù)雜邏輯下的對象傳遞,比如監(jiān)聽器的傳遞
ThreadLoal的值在table數(shù)組中的存儲位置總是為ThreadLocal的reference字段所標(biāo)識的對象的下一個位置把夸。ThreasdLoacal的set和get方法所操作的對象都是當(dāng)前線程的localValues對象的table數(shù)組而线,因此在不同的線程中訪問同一個ThreadLocal的set和get方法,他們對ThreadLocal所做的讀寫操作僅限于各自線程的內(nèi)部恋日,從而實現(xiàn)在多個線程中互不干擾的存儲和修改數(shù)據(jù)膀篮。

Looper的工作原理
Looper在Android的消息機(jī)制中扮演著消息循環(huán)的角色,就是不停的從MessageQueue中查看是否有新消息岂膳,如果有消息就立刻處理誓竿,否則就一直阻塞在哪里首先在構(gòu)造方法中創(chuàng)建一個MessageQueue即隊列消息,然后將當(dāng)前的對象保存起來Looper除了prepare方法外谈截,還提供了prepareMainLooper方法筷屡,這個方法主要是給主線程也就是ActivityThread創(chuàng)建Looper使用的,其本質(zhì)也是通過prepare方法來實現(xiàn)的簸喂。由于主線程的Looper比較特殊毙死,所以Looper提供了一個getMainLooper方法,通過它可以再任何地方獲取到主線程的Looper喻鳄。Looper也是可以退出的扼倘,Looper提供了quit和quitSafely來退出一個Looper,二者的區(qū)別是:quit會直接退出Looper除呵,而quieSafely只是假定一個特殊標(biāo)記再菊,然后把消息隊列中的已有消息處理完畢后才安全退出。Looper退出后颜曾,通過Handler發(fā)送消息失敗纠拔,這個時候Handler的send方法會返回false。在子線程中泛豪,如果手動為其創(chuàng)建Looper稠诲,那么在所有的事情完成以后應(yīng)該調(diào)用quit方法來終止消息循環(huán),否則這個子線程就會一直處于等待狀態(tài)诡曙,而如果想退出Looper以后吕粹,這個線程就會立刻終止,岗仑,因此建議不需要的時候終止Looperloop方法是個死循環(huán)匹耕,唯一跳出循環(huán)的方式是MessageQueue的next方法返回null。當(dāng)Looper的quit方法被調(diào)用時荠雕,Looper就會調(diào)用MessageQueue的quit或者quitSafely方法來通知消息隊列退出稳其,當(dāng)消息隊列被標(biāo)記為退出狀態(tài)時驶赏,它的next方法就返回null。Loop必須退出既鞠,否則loop循環(huán)就會無限循環(huán)下去煤傍。loop方法會調(diào)用MessageQueue的next方法,而next方法是一個當(dāng)沒有消息時 是一個阻塞線程嘱蛋,便會導(dǎo)致Looper也會阻塞在那里蚯姆。當(dāng)MessageQueue的next方法返回了新的消息,Looper就會處理這條消息:msg.target.disapatchMessage洒敏,這里msg.target是發(fā)送這條消息的Handler對象龄恋,消息交給dispatchMessage方法來處理。而這個dispatchMessage方法是在創(chuàng)建Handler時所用的Looper中執(zhí)行凶伙。這樣就把代碼邏輯切換到主線程郭毕。

handler,looper和Measge之間的如何協(xié)作的

image.png

主線程向子線程發(fā)送消息:

首先handler肯定是要創(chuàng)建到子線程當(dāng)中函荣,用于接收主線程發(fā)來消息進(jìn)行處理显押,但是,因為子線程沒有l(wèi)ooper對象傻挂,首先需要調(diào)用looper.prepare(),當(dāng)主線程發(fā)來消息后乘碑,已經(jīng)準(zhǔn)備好的looper同樣會去消息隊列當(dāng)中循環(huán)消息,交給handler金拒,但handler真正能夠使用該數(shù)據(jù)還得調(diào)用looper.loop();

Measge可以通過wait來區(qū)分消息
Mesage通過takte來區(qū)分handler

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末兽肤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子殖蚕,更是在濱河造成了極大的恐慌,老刑警劉巖沉迹,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件睦疫,死亡現(xiàn)場離奇詭異,居然都是意外死亡鞭呕,警方通過查閱死者的電腦和手機(jī)蛤育,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來葫松,“玉大人瓦糕,你說我怎么就攤上這事∫该矗” “怎么了咕娄?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長珊擂。 經(jīng)常有香客問我圣勒,道長费变,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任圣贸,我火速辦了婚禮挚歧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吁峻。我一直安慰自己滑负,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布用含。 她就那樣靜靜地躺著矮慕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪耕餐。 梳的紋絲不亂的頭發(fā)上凡傅,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機(jī)與錄音肠缔,去河邊找鬼夏跷。 笑死,一個胖子當(dāng)著我的面吹牛明未,可吹牛的內(nèi)容都是我干的槽华。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼趟妥,長吁一口氣:“原來是場噩夢啊……” “哼猫态!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起披摄,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤亲雪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后疚膊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體义辕,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年寓盗,在試婚紗的時候發(fā)現(xiàn)自己被綠了灌砖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡傀蚌,死狀恐怖基显,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情善炫,我是刑警寧澤撩幽,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站箩艺,受9級特大地震影響摸航,放射性物質(zhì)發(fā)生泄漏制跟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一酱虎、第九天 我趴在偏房一處隱蔽的房頂上張望雨膨。 院中可真熱鬧,春花似錦读串、人聲如沸聊记。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽排监。三九已至,卻和暖如春杰捂,著一層夾襖步出監(jiān)牢的瞬間舆床,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工嫁佳, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留挨队,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓蒿往,卻偏偏與公主長得像盛垦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子瓤漏,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353