Handler消息機制介紹,流程梳理

前言

Handler 是Android 的消息處理機制,其主要有兩個作用:

1.發送消息,延遲處理。你可以通過Handler 來發送一個Message 或者Runnable 對象,並在收到消息時處理他們,另外可以指定延遲時間,以便在將來執行。

2.線程間通訊。簡單來說就是在不同於Handler 所屬的線程發送消息,在Handler 的依附線程中接受並處理消息。這也就要求Handler 實例必須與線程和線程的消息隊列相關聯,當創建一個新的Handler對象時,需要綁定到創建它的線程和線程的消息隊列上,通過將Message/Runnable 添加到消息隊列中,在它們從消息隊列中出來時執行。

Handler 是整個消息機制的門面類,用來發送和接收消息。提供了兩種形式的消息分發和處理,一種是post 一個Runnable 對象,另外一種是send 一個Message對象。

基本使用

發送和處理Runnable

Handler 支持通過 post 的相關方法來發送一個 Runnable 對象進入消息隊列,當收到相應的消息時被調用。相關的方法有{@link #post}, {@link #postAtTime(Runnable, long)}, {@link #postDelayed}

Handler handler = new Handler();

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        // todo something
    }
}

// 立即發送
handler.post(runnable);

其他API介紹:

android.os.Handler#postDelayed(java.lang.Runnable, long)
將Runnable 添加到消息隊裏中,並在指定的延遲後執行

android.os.Handler#postAtTime(java.lang.Runnable, long)
將Runnable 添加到消息隊裏中,並在指定的時間執行

發送和處理Message

Handler 允許發送一個 message對象,實現 Handler的{@link #handleMessage}方法,在這裏處理接收到的Message。相關的方法有{@link #sendEmptyMessage}, {@link #sendMessage}, {@link #sendMessageAtTime}, {@link #sendMessageDelayed} 等

private Handler mHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        // 處理消息 message
    }
};

// 獲取 message
Message message = mHandler.obtainMessage(0);
// 發送 message 
mHandler.sendMessage(message);

其他API介紹:

android.os.Handler#sendMessageDelayed
將Message 添加到消息隊裏中,並在指定的延遲後發送,在handler的 handleMessage 中處理消息

android.os.Handler#sendMessageAtTime
將Message 添加到消息隊裏中,並在指定的延遲後發送,在handler的 handleMessage 中處理消息

流程梳理

使用Handler 發送一個Message時,在 MessageQueue 的enqueueMessage 方法中會對消息按時間優先級進行入隊操作。
與線程綁定的Looper 不斷的從MessageQueue中取消息進行發送(queue.next()),當某個Message 執行完畢後,釋放資源並加入到緩存隊列中以重複使用(msg.recycleUnchecked())

獲取消息

雖然Message的構造函數是公共的,我們可以通過new 關鍵字來自行創建一個Message 對象,但是系統更推薦我們使用 {Message.obtain()}或{Handler#obtainMessage.obtainMessage()}相關的方法獲取對象。

Handler 的消息獲取內部採用了享元模式來實現,Message 內部有一個全局的緩存池sPool,保存着回收的Message 對象。當使用obtain() 方法時,會先從緩存池中獲取Message 對象,如果沒有再去創建一個新對象。在消息轉發完成後,會對使用的消息進行回收再利用,節約因頻繁創建對象帶來的內存開銷。

發送消息

Handler 提供了很多的 send 和post 的方法,這些方法最終都會走到android.os.Handler#enqueueMessage 這個方法,而在這個方法裏又會調用MessageQueue 的enqueueMessage 方法執行消息的入隊操作。
handler 調用流程

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

消息入隊

MessageQueue 內部維護了一個消息隊列,而 enqueueMessage(Message msg, long when) 方法主要處理的就是入隊操作,對新來的Message 根據絕對時間進行優先級排序,絕對時間小的Message往前排。

boolean enqueueMessage(Message msg, long when) {
        ...省略其他代碼
        
        msg.when = when;
        Message p = mMessages;

        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;

        } else {
            ...省略其他代碼
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                ...省略其他代碼
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }
        ...省略其他代碼
}

消息出隊

在Handler 機制中,Looper類的主要作用是負責線程的消息循環,在Looper.loop() 方法中,循環不斷的從MessageQueue.next() 函數中獲取下一個消息進行派發,在發送完畢後回收釋放該消息,完成消息的出隊。

public static void loop() {
    final Looper me = myLooper();
    ...省略其他代碼
    
    final MessageQueue queue = me.mQueue;
    for (;;) {
        // 從消息隊列中獲取下一個要執行的Message
        Message msg = queue.next(); // might block
        ...省略其他代碼

        // 執行消息的分發
        msg.target.dispatchMessage(msg);
            
        ...省略其他代碼
        // 釋放、回收Message,完成消息出隊
        msg.recycleUnchecked();
    }
}

理解

Handler:是消息機制的門面類,主要負責發送和處理消息,同樣還有移除消息的功能。
Message:即要發送的消息,包含消息標記、消息數據、執行時間、處理響應的Handler等。
MessageQueue:內部包含一個由Looper調度的消息隊列
Looper:負責線程的消息循環,從MessageQueue 中獲取要發送的消息

以一家運輸公司做個比喻
在這裏插入圖片描述

運輸公司(Handler):承接貨物的運輸業務,負責貨物的接受和發送。
運輸車(Message):貨物的載體,附帶一些信息,比如所屬公司(Handler)、編號(what)、運輸的貨物(arg1、arg2、obj)、發車時間(when)等等
備用車輛(Message.sPool):空閒狀態的運輸車,當有新需求的時候負責提供運輸車輛
執行運輸任務的車隊(MessageQueue.mMessages):因任務而組成的運輸車隊,根據每輛車發車時間進行車輛排序。
調度站(Looper):負責對運輸的車隊車輛進行逐個派發

當客戶有需求時,運輸公司會從空閒的運輸車中安排一輛車爲其服務,貨物打包好後加入執行運輸任務的車隊中。運輸車隊對新加入的運輸車輛按發車時間進行排序。另一邊,調度站如果發現有要執行任務的車隊,則逐個對運輸車輛進行派發,“下一輛、下一輛…”,如果沒有,則處於等待的狀態。運輸車輛執行完當前任務後,把攜帶的信息清空,加入到備用車輛中,以供下次繼續使用。

源碼分析

本篇先對Handler 機制做個大概的介紹,源碼部分將對Message、MessageQueue、Looper 分別做分析。

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