簡介
Q:什么是 Handler
A:Handler 是 Android 系統里的消息處理機制,下面的一段文字是在 Handler 源碼上的注釋,它闡述了 Handler 作為消息處理機制的作用。
Handler 是一個可以通過關聯一個消息隊列來發送或處理消息,Runnable對象。每個Handler都關聯一個單個的線程和消息隊列.當你創建一個新的Handler的時候它就將被綁定到一個線程或線程上的消息隊列,從那時起,這個Handler就將為這個消息隊列提供消息或Runnable對象,處理消息隊列釋放出來的消息或Runnable對象.
Q:Handler 的主要用途
A:(1)能夠定時執行消息和Runable對象;(2)可以將一個執行的動作放在不同的線程中。
Q:Handler 的主要用法
A:通過一系列的 post、send 方法發送消息,通過 handleMessage
來處理消息。
post(Runnable r)
postAtTime(Runnable r, long uptimeMillis)
postDelayed(Runnable r, long delayMillis)
sendEmptyMessage(int what)
sendMessage(Message msg)
sendMessageAtTime(Message msg, long uptimeMillis)
sendMessageDelayed(Message msg, long delayMillis)
Q:與 Handler 相關的一些類
A:與 Handler 相關的主要是 Message,MessageQueue,Looper這些類。
Message:消息的載體。
MessageQueue:消息隊列,主要功能是向消息池中投遞消息和取走消息。
Looper:線程的消息循環處理器。
深入
Q:各個類的對應關系
A:每個線程只允許包含一個 Looper,每個 Looper 包含一個 MessageQueue。每個線程上可以生成多個Handler,Handler默認使用的是當前線程上的 Looper 。
Q:如何確保每個線程上只有一個 Looper,且各個線程之間互不干擾
A:Looper 類的實例必須通過方法 prepare()
創建,一個線程中多次調用 prepare()
方法將會拋出異常。Looper 實例將會保存在靜態變量 ThreadLocal 中,ThreadLocal 實現了線程本地存儲的功能,這樣放入 ThreadLocal 對象的 Looper 對象就與線程關聯在一起。
Q:消息是如何按時間分發的
A:向 MessageQueue 發消息使用的 enqueueMessage
方法,其方法在插入消息時根據時間來排序,時間早的插在前面。消息隊列的組織利用了 Message 類中的 next 指針形成一個從頭指向尾的單向鏈表,插入時計算是否需要喚醒處理線程。
// 如果新來的消息時間比隊列頭的消息短則成為新的隊列頭,喚醒處理線程
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
...
}
Q:消息隊列是如何掛起,又是如何喚醒的
A:MessageQueue 中的消息循環在方法 next() 中,而掛起和喚醒則是通過 native 層來實現。在 native 層的 Looper 類構造函數中創建了管道,同時使用 epoll 來監聽讀管道。epoll 的作用是監聽管道上的數據,管道則用于線程間通信。
nativePollOnce(ptr, nextPollTimeoutMillis);
在 MessageQueue 的 next() 方法中會調用 nativePollOnce()
方法,該方法最后通過調用 epoll_wait()來執行等待操作。
同樣,調用 nativeWake() 可以喚醒處理線程。nativeWake()最終會調用到 native 層的 Looper 類的 wake()方法。wake() 方法通過向管道中寫入數據來喚醒消息處理線程。
Q:SyncBarrier 是什么
A:SyncBarrier 或者叫“同步分割欄”,在 MessageQueue 類中有一個方法叫 enqueueSyncBarrier(long when)
,可以調用這個方法在消息隊列中插入一條沒有 Handler 對象的消息,這條不帶 Handler 對象的消息就稱為 “SyncBarrier”(開發者需要調用Looper的postSyncBarrier()來打入)。
SyncBarrier就像一個卡子,卡在消息鏈表中的某個位置,當消息循環不斷從消息鏈表中摘取消息并進行處理時,一旦遇到那么即使在分割欄之后還有若干已經到時的普通Message,也不會摘取這些消息了。此時如果還有消息需要處理,可以使用 setAsynchronous()
方法給消息做上標志。這也是‘普通Message’和‘異步Message’的區別了。
總結
概括的描述,無非就是通過 Handler 向 Looper 的 MessageQueue 發送 Message 消息,再由 Looper 在消息循環里處理。關于 Android 的消息機制能說的暫時就那么多了,詳情可以結合代碼源代碼細細思考。
一篇更詳細的 Handler 機制——聊一聊Android的消息機制