Handler消息處理機制總結

一、從構造函數開始

Handler構造函數

可以看到,Handler的構造函數里,關聯了Looper(通過Looper.myLooper()方式取得)、Queue(MessageQueue,從Looper中取得)、Callback()、async.

接下來,看一下 Looper.myLooper():

Looper.myLooper()

myLooper()取得的Looper是存儲在ThreadLocal中的。通過looper.prepare()初始化并存儲:

Looper.prepare()

通過方法,可以看到,prepare()函數只能被調用一次,不然會throw Exception。這樣可以保證,一個ThreadLocal中只存在一個Looper。

再看Looper的構造函數:

new Looper()

在looper的構造方法里,主要做了兩件事:

1、創建一個looper管理的消息隊messageQueue;

2、獲得當前的線程;

到這里,Handler的構造函數,基本流程跑完。總結一下,new 一個handler的時候,會得到一個綁定在ThreadLocal中的Looper實例、一個與Looper綁定的MessageQueue實例,這三個實例對象互相綁定,從而進行信息交流。


二、信息發送流程。

handler通過sendMessage()、sendMessageDelayed()、sendMessageAtTime()等方法發送信息,最終這些方法都會走入同一個方法:enqueueMessage()

handler.enqueueMessage()

在enqueueMessage()方法中,先是將本handler對象賦值msg.target.之后執行了messageQueue的消息隊列插入消息操作MessageQueue.enqueueMessage():

MessageQueue.enqueueMessage()

此函數執行的是單鏈表的插入操作,從此也可以看出。MessageQueue實際上是由單鏈表實現的。


三、消息處理流程。

將Message插入MessageQueue之后,我們知道。與MessageQueue綁定的Looper會調用 loop()方法一直循環遍歷MessageQueue:

Looper.loop()

清晰明了,獲取當前looper和與其對應的MessageQueue。通過一個for(;;)死循環,從MessageQueue中遍歷獲取Message。這邊注意,messageQueue.next()方法中如果沒有Message,會在next()方法中block住,直到有Message被enQueue入MessageQueue隊列中,next()方法繼續執行,loop()也可以瞬間得到Message。而只有在looper調用quit()或quitSafely()方法,messageQueue的next()方法才會返回null(此時MessageQueue同樣調用了quit()方法),此時loop的無限循環也將結束。

looper.quit()和looper.quitSafely()的區別是:quit()直接退出Looper,quitSafely()只是設置一個退出標志,等消息隊列中的消息處理完畢,就會退出Looper,這時候Handler的send方法返回false。如果在子線程中手動創建了Looper,要記得退出Looper,不然這個線程會一直處于等待轉態,如果退出了,這個線程也會被終止。

接下來,我們來看一下 MessageQueue的next()方法:

MessageQueue.next() part1
MessageQueue.next() part2

就像我們之前說的那樣,如果單向鏈表中有Message,便取出這個Message return出去,如果鏈表中已經沒有Message,便通過Binder.flushPendingCommands() ?block當前操作。


回到Looper.loop()中,當looper從MessageQueue中得到Message之后,便會調用msg.target.dispatchMessage(msg)去處理Message。之前我們提到過,在Handler發送消息的enqueueMessage()方法中,已經將當前Handler賦值給了msg.target.此時,便是將發送message的handler變量取出,調用其dispatchMessage(msg)方法處理Message。

Handler.dispatchMessage(msg)

Handler的消息處理過程如下:

首先先檢查Message的callback是否為空,不為空就通過handleCallback來處理,Message的callback是一個Runnable對象,實際上就是Handler的post方法所傳遞的Runnable參數

其次檢查mCallback是否為null,不為null就調用mCallback的handleMessage方法來處理,Callback是個接口,定義如下:

public interface Callback {

?? ?public boolean handleMessage(Message msg); ? ?

}

通過Callback可以采用如下方法創建Handler handler = new Handler(callable)。在日常開發中,創建Handler最常見的方式是派生一個Handler的子類并且重寫它的handleMessage方法,另外一種是傳入一個Callback,并實現callback的handleMessage方法。

最后調用Handler的handleMessage方法來處理消息。

處理過程的流程圖:


Message處理流程圖


四、Handler使用注意事項

1、創建massage對象時,推薦使用obtain()方法獲取,因為Message內部會維護一個Message池用于Message的復用,這樣就可以避免 重新new message而沖內心分配內存,減少new 對象產生的資源的消耗。

2、handler 的handleMessage方法內部如果有調用外部activity或者fragment的對象,一定要用弱飲用,handler最好定義成static的,這樣可以避免內存泄漏;為什么呢?因為一但handler發送了消息。而handler內部有對外部變量的引用,此時handler已經進入了looper的messageQueue里面。此時activity或者fragment退出了可是區域,但是handler內部持有其引用且為強引用時,其就不會立即銷毀,產生延遲銷毀的情況。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,460評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,067評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,467評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,468評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,184評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,582評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,616評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,794評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,343評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,096評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,291評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,863評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,513評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,941評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,190評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,026評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,253評論 2 375

推薦閱讀更多精彩內容