如有引用參考請詳註出處,感謝
Android 是以消息推動系統的機制,所以我們要好好了解 Handler 機制,以下會以使用 Handler 分析源碼 來下手;這篇是分析 Java 層的消息機制
由於 Android 是 消息驅動 的系統,所以要先來介紹 Handler,Handler 機制主要有分為 4 個組成
類 | 說明功能 |
---|---|
Handler | 真正處理事件的地方 |
Looper | 循環檢查是否有要傳輸的事件,從 MessageQueue 中獲取事件,並交給 Handler 處理(假如列隊為空就進入休眠) |
MessageQueue | 儲存需要做的事情,一般來說止允許保存相同類型的 Object、Message 除存的數據結構為 佇列 |
Message | 需要做的事件 |
其實一開始會很難發現 Handler & Thread 之間的關係,我們可以先看看這幾個結論在看看程式如何實現它
Thread & Handler 是一對多的關係
應用開發時常使用到 Handler 類,它主要有兩個做用
接收 處理 Message
將 Message 存入 MessageQueue 中
在上面分發事件有三種方法,並且 這三種分發方式有 1 先後順序,只要前面被處理,就不會使用後面的方式處理
Handler#handleMessage
Function這種方式就會變成了一種循環
透過 Handler 把訊息壓到 MessageQueue,方式有 Post & Send 兩種系列,並且可以 2 控制發送的時間,以下寫幾個常用的
函數 | 功能 |
---|---|
boolean post(Runnable r) | 直接發出訊息 |
boolean postAtTime(Runnable, long updatetimeMillis) | 在固定(規定)時間再發出該條訊息 |
函數 | 功能 |
---|---|
boolean sendEmptyMessage(int what) | 直接發送訊息 |
boolean sendMessageArFrontOfQueue(Message msg) | 把消息發送到訊息隊列最前面 |
boolean sendMessageAtTime(int what, long updatetimeMillis) | 在固定(規定)時間再發出該條訊息 |
boolean sendMessageDelayed(Message msg, long delayMillis) | 延遲幾毫秒後發送該訊息 |
Post 實現方式如下
名稱 | 參數 : 回傳 | 解釋 |
---|---|---|
post | Runnable : boolean | 接收一個 Runnable 對象作為 Message |
postAtTime | Runnable, long : boolean | 接收一個 Runnable 對象作為 Message,並在等待的規定時間發送 Message |
sendEmptyMessage | int : boolean | 發送一個使用者規定的 int 訊息,在由使用者自己處理 |
sendMessageAtTime | Messge, int : boolean | 發送一個使用者規定的 int 訊息,在由使用者自己處理 |
sendMessageDelayed | Messge, long : boolean | 在等待的規定時間後 (延遲) 發送 Message |
dispatchMessage
、handleMessage
這兩個函數作為 Handler 處理 Message舉例:以下是 WMS 在初始化時就使用 (DisplayThread) Handler#runWithScissors 這個函數來達到先執行 Runnable 任務的功能 (如果不先創建 WMS 則後面使用則會出問題)
這裡的重點是 Handler 中的 runWithScissors 函數: 1 比對 Looper 若是就是 Handler 中的 Thread,則直接執行,2 創建 BlockingRunnable 對象 (主要分析 BlockingRunnable)
BlockingRunnable 是 Handler 中的內部類
名稱 | 參數 : 回傳 | 解釋 |
---|---|---|
enqueueMessage | Message, long : boolean | 在指定時間內壓入佇列中 |
next | void : Message | 元素拉出佇列 |
removeMessages | Handler, int, Object : void | 移除特定元素 |
removeMessages | Handler, Runnable, Object : void | 移除特定元素 |
新建列隊
由建構函數 中的 nativeInit 方法組成
元素入隊列 enqueueMessage
元素出隊列 next
刪除元素
銷毀列隊,透過本地函數 nativeDestory 銷毀一個 MessageQueue
連接於 Looper 的建構函數,當 Looper 創建時 MessageQueue 就一同創建
IdleHandler 是 MessageQueue 內的一個 interface,它可以在 MessageQueue 沒有消息時讓使用者知道,並決定如何處理
同樣分析 next 方法,可以看到 一個 MessageQueue 最多設定 4 個 IdleHandler
名稱 | 參數 : 回傳 | 解釋 |
---|---|---|
myLooper | void : Looper | 以當前線程為主,取得當前 Thread 的 Looper |
getMainLooper | void : Looper | 取得主線程的 Looper |
最後 Looper 則是讓整個 Hanler 機制循的動力,有 Looper 的推動 Handler 才能正常接收、發送資訊
Looper 中包含了一個 MessageQueue(在建構函數中建構的)
當你每創建一個線程就必須為這個線程準備 Looper,否則在 Handler 發送消息時就會 crush (上面有說到會檢查),創建主要有以下步驟
ThreadLocal 這裡大概提及,ThreadLocal 也就是線程隔離,使用線程 Thread 作為 Key 儲存,而 Value 就是你要拷貝到每個線程的數據(每個子線程都持有一個數據)
這裡要注意 1 ThreadLocal 是泛型,2 在 Looper 裡面就是一個靜態變數
當你建立一個 Handler 時,在 Handler construct 就會透過當前的線程取得 Looper
當一個普通線程要使用 Handler 時 必須要有 Looper 的預前準備工作
a. 它有一個很重要的屬性 static final ThreadLocal,它是一個 靜態變量,意味著每個線程共享此屬性,但 ThreadLocal 是特殊的變量,讓每一個 Thread 都有一個 Looper 對象
b. 可看出 prepare 時它內部會自己創建一個 Looper 對象,並且 Looper 的建構函數也是私有的
c. Looper 被創建時就會自己準備一個 MessageQueue
Looper 跟 Handler 的關係可以從 new Handler() 這個建構函數 中看出,它是透過 myLooper 方法,透過目前的線程在 ThreadLocal 中 取得該當前線程所擁有的 Looper
這也就是上面在準備時為何要調用 Looper.prepare() 這個方法,如果沒準備就不一定會有 Looper
主線程的 Looper 是不可以關閉的,並且使用類同步
sMainLooper = myLooper(); 把目前的 Thread 作為內部靜態類維護,並可以透過,getMainLooper 隨時取得
一般線程必須自己建造 Handler 處理訊息,不過其實 ActivityThread 內部已經有自己的 Handler 實現 (並且不能 Override)
Looper#loop,首先取得目前線程所擁有的 Looper,再取出 Looper 內部有的 MessageQueue,最後無限循環整個消息對列
ThreadLocal 的功能主要是做到線程隔離 (用線程隔離數據),簡單來說可以把 ThreadLocal 當作一個 Map (但實際來說它並不是 Map),它的 Key 是 Thread
,Value 是一個泛型
詳細 ThreadLocal 分析有寫在 Java 多線程-進階
它使用目前呼叫它的 Thread.currentThread 作為 Key 存入,Value 是泛型
依照當前線程 (currentThread),取的 Value
消息機制就是通過每個 Thread 儲存不同的 Looper 在 ThreadLocal 中,當有需要時就已 Thread 作為 key 來取得 Looper
Handler & Thread
從上面可以看出 Handler & Thread 的關係是建立在,ThreadLocal 取得 Looper,而 Handler 建構函數又取得當前 Thread
一個 Thread 對應一個 Looper,一個 Looper 對應一個 MessageQueue
Android 進階