說說 Android 里的 Handler 的機制

簡介

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的消息機制

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容