android 異步消息處理機制 — AHandler

1. 引入 ALooper、AHandler、AMessage

在 android multimedia stagefright 的框架代碼中,通篇都是這幾個類的身影,所以熟悉 android 多媒體框架的第一步必須理解這幾個類的含義。

這幾個類是爲了實現異步消息機制而設計的,這裏有兩個概念 “異步” & “消息機制”,下面詳細說明一下。

同步和異步概念區別比較簡單,可以舉個例子說明:

  1. 同步:肚子餓了去飯店,點好菜後坐着等服務員上菜,什麼時候菜做好了,你才能結束等菜。
  2. 異步:掏出手機,打開外賣軟件,下單,這個時候你就可以去做別的事情,而不是乾等着,等到時候飯店做好菜了,小哥自然送上門。

可以看出,異步處理更加靈活自由,對於需要兼顧編碼、解碼、顯示、音頻輸出等功能的多媒體框架,無疑需要異步處理,來降低 cpu 的使用率。

我們知道,想要我們的程序執行一些事情要麼同步要麼異步,而消息機制是異步的一種實現方式。消息機制完美的解決了多線程間的同步問題,使程序設計更加便捷明瞭。下面的章節簡單說明一下原理。

2. 消息機制原理概述

首先三個類的職責可以從字面理解:

  1. AMessage:消息載體
  2. ALooper:消息循環分發
  3. AHandler:消息處理

消息機制原理流程如下圖:

image

首先由 創建一個消息隊列,這個消息隊列在一個單獨的線程中輪詢,由其他線程產生的消息 會被投遞到消息隊列中, 持續不斷的輪詢消息隊列,從消息隊列中取出 ,並分發給對應的 進行消息處理。

這裏有幾點需要注意:

  1. 一個 ALooper 消息隊列中可以有多個 AHandler 註冊其中,但是一個 AHandler 不能註冊在多個 ALooper 下
  2. ALooper 啓動後(線程啓動),會不斷輪詢,有AMessage 就拋給指定的 AHandler 處理。並且在發現自己的消息隊列中沒有任何消息時,會等待,不會一直跑,從而降低 CPU 的佔用率

這樣,三個類各司其職、緊密合作,維持消息框架處理機制的正常運轉。

附源碼中消息機制相關代碼:

1. NuPlayerDriver.cpp
NuPlayerDriver::NuPlayerDriver(pid_t pid)
    ...
{
    mLooper = new ALooper();
    
    mLooper->setName("NuPlayerDriver Looper");
    
    // 開啓線程,進行消息隊列循環
    mLooper->start(
            false, /* runOnCallingThread */
            true,  /* canCallJava */
            PRIORITY_AUDIO);
    
    // NuPlayer 繼承自 AHandler,用於進行消息處理
    mPlayer = new NuPlayer(pid);
    // 註冊 AHandler
    mLooper->registerHandler(mPlayer);
}

2. Nuplayer.cpp
// Nuplayer 是 AHandler 的實現類,用於消息處理
void NuPlayer::setDataSourceAsync(const sp<IStreamSource> &source) {
    // 創建一個消息,第二個參數指定處理的 AHandler
    sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);

    // 投遞到消息隊列中去,後續由 ALooper 分發到對應的 AHandler 中處理
    msg->post();
}

// AHandler 的 virtual 方法,消息在這個函數中進行處理
void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatSetDataSource:
        {
            // 消息處理
        }
}

3. 源碼詳解

後續補上

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