Handler機制原理和常見問題 基本元素 工作流程 常見問題

基本元素

Handler

用於處理消息,包括將發送消息到消息隊列,和從消息隊列中分發出去。

Message

用戶對屏幕操作而產生的信息。

Looper

一個死循環,不停地輪詢等待線程給它的消息。

MessageQueue

存放消息的隊列,是一個優先級隊列,當新插入一個消息的時候,會先和隊列內的消息的執行時間做對比,然後插入,執行時間越短,優先級越高,具體方法在enqueueMeassage()方法中。

工作流程

首先可以把整個過程當成一個生產流水線,handler是機器手,message就是產品,messagequeue就是流水線的傳輸帶,handler將message發送到傳輸帶messagequeue上,message按照時間順序排列在運輸袋子上,looper就是發動機帶動轉軸,把message運輸出去,最後又是handler把message分發出去。

具體的方法過程如下:

Handler首先調用sendMessage(),而sendMessage又調用MessageQueue的enqueueMessage()方法,該方法的目的是把message存在消息隊列中。

現在消息已經在消息隊列中了,需要一個動力去讓這些消息被挨個的處理,於是我們就需要looper中的loop函數,它會調用queue.next()方法,這就取到了一個隊列中的message,然後handler繼續調用dispatchMessage()方法,該方法就包含了handler的handleMessage()方法,然後就會循環該過程。

常見問題

1.Looper如何停下來

當消息隊列是空的時候,loop執行queue.next()的時候會阻塞,此時就可以停下來。

2.一個線程中幾個handler

隨便多少個,new一個有一個。

3.一個線程有幾個looper

一個,由threadlocal決定。一個線程裏面有一個threadlocalMap類型的變量,裏面保存的是threadlocal,所以threadlocal是個key,value鍵值對,Looper的構造函數是個私有函數,只有在prepare()方法中初始化,在該方法中,set方法會獲取當前線程,獲取當前threadlocalMap,一個線程只對應一個map,map中一個key對應一個value,key是threadlocal,value就是Looper,所以一個線程綁定一個looper。

4.Handler爲什麼會內存泄漏,解決方案

Handler持有Activity。因爲handler是個匿名內部類,可以持有外部類對象,所以handler持有activity。內存泄漏和handler的機制有關,message持有handler,handler又持有activity,message又有延遲處理的情況,所以會一直存在消息隊列中,這時候messageQueue又持有activity,只要message不及時處理,activity就不會被回收。解決方案是:activity弱引用。

5.爲什麼在主線程中可以直接new handler

當啓動app的時候,會先啓動Luncher,然後在linux層,會調用zygote去給每個應用建立一個虛擬機,此時會調用activityThread再去使用main方法,裏面就有prepareMainLooper方法,此時可以知道所有組件都是圍繞主線程looper,以消息存在。

6.怎麼在子線程中new一個handler

先Looper.prepare(),在new handler,最後Looper.loop()

7.子消息Looper,沒有消息怎麼辦

消息隊列沒有消息,會調用nativePollOnce方法,這個方法會進去等待狀態,此時會調用linux的epoll函數並傳入-1,epoll函數會將結果傳入linux的消息隊列中,若這個值是-1,則會陷入永久等待狀態,線程掛起。

8. Looper怎麼退出

調用messageQueue.quit方法,這個過程中,首先removeAllmessageLocked(),把所有的消息全部移出去。此時調用了recycleUnchecked()方法,將消息內部變量賦值爲null,然後調用nativeWake(),這個和epoll相反,它喚醒了線程,並返回一個爲null的msg,Loop中for循環就會終止。

9.主線程需要釋放looper嗎

不能,AMS圍繞handler管理,四大組件也是靠主線程的Looper處理操作

10.多個handler往消息隊列放消息怎麼保證線程安全

加鎖,使用synchronized

11.怎麼生成一個message

使用享元設計模式,提前已經存在了一個消息隊列,已經處理完的消息,會被賦值爲null,並且用頭插法存在這個列表中。當使用obtain的時候會從該消息隊列中獲取一個空消息

12.Looper爲何不會讓應用卡死

二者之間,ANR的原因是消息沒有被及時處理,而looper沒有消息時候會進入睡眠狀態釋放線程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章