android 异步消息处理机制 — AHandler

1. 引入 ALooper、AHandler、AMessage

在 android multimedia stagefright 的框架代码中,通篇都是这几个类的身影,所以熟悉 android 多媒体框架的第一步必须理解这几个类的含义。

这几个类是为了实现异步消息机制而设计的,这里有两个概念 “异步” & “消息机制”,下面详细说明一下。

同步和异步概念区别比较简单,可以举个例子说明:

  1. 同步:肚子饿了去饭店,点好菜后坐着等服务员上菜,什么时候菜做好了,你才能结束等菜。
  2. 异步:掏出手机,打开外卖软件,下单,这个时候你就可以去做别的事情,而不是干等着,等到时候饭店做好菜了,小哥自然送上门。

可以看出,异步处理更加灵活自由,对于需要兼顾编码、解码、显示、音频输出等功能的多媒体框架,无疑需要异步处理,来降低 cpu 的使用率。

我们知道,想要我们的程序执行一些事情要么同步要么异步,而消息机制是异步的一种实现方式。消息机制完美的解决了多线程间的同步问题,使程序设计更加便捷明了。下面的章节简单说明一下原理。

2. 消息机制原理概述

首先三个类的职责可以从字面理解:

  1. AMessage:消息载体
  2. ALooper:消息循环分发
  3. AHandler:消息处理

消息机制原理流程如下图:

android 异步消息处理机制 — AHandler_第1张图片

首先由 创建一个消息队列,这个消息队列在一个单独的线程中轮询,由其他线程产生的消息 会被投递到消息队列中, 持续不断的轮询消息队列,从消息队列中取出 ,并分发给对应的 进行消息处理。

这里有几点需要注意:

  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 &source) {
    // 创建一个消息,第二个参数指定处理的 AHandler
    sp msg = new AMessage(kWhatSetDataSource, this);

    // 投递到消息队列中去,后续由 ALooper 分发到对应的 AHandler 中处理
    msg->post();
}

// AHandler 的 virtual 方法,消息在这个函数中进行处理
void NuPlayer::onMessageReceived(const sp &msg) {
    switch (msg->what()) {
        case kWhatSetDataSource:
        {
            // 消息处理
        }
}

3. 源码详解

后续补上

你可能感兴趣的:(android,multimedia)