Android native异步消息机制

谷歌在Android native层实现的一个异步消息机制,在这个机制中几乎不存在同步锁,所有的处理都是异步的,将变量封装到一个消息AMessage结构体中,然后放到队列中去,后台专门有一个线程会从这个队列中取出消息然后执行,执行函数就是onMessageReceived

AMessage类

struct AMessage : public RefBase {
    //构造函数,包括两个参数,第一个参数指明这是个什么消息,用于在onMessageReceived处理分支中进行匹配,第二个参数target用于后台线程在处理这个消息的时候知道发给哪个类处理
    AMessage(uint32_t what = 0, ALooper::handler_id target = 0);
    void setWhat(uint32_t what);
    uint32_t what() const;
    void setTarget(ALooper::handler_id target);
    ALooper::handler_id target() const;

    void clear();
    //这个消息类中定义了一堆set和find方法,用于在在传递消息过程中携带各种信息
    void setObject(const char *name, const sp &obj);
    void setBuffer(const char *name, const sp &buffer);
    void setMessage(const char *name, const sp &obj);
    bool findBuffer(const char *name, sp *buffer) const;
    bool findMessage(const char *name, sp *obj) const;
    void post(int64_t delayUs = 0);
protected:
    virtual ~AMessage();  析构函数
private:
    uint32_t mWhat;
    ALooper::handler_id mTarget;
    两个重要的私有成员变量
};

使用方法
正如开头部分看的那样,构造一个消息的过程如下:

void NuPlayer::start() {
    (new AMessage(kWhatStart, id()))->post();
}
void AMessage::post(int64_t delayUs) {
    gLooperRoster.postMessage(this, delayUs);
}

AHandler类分析----消息处理类的父类

struct AHandler : public RefBase {
    AHandler()
        : mID(0) {  // mID的初始值为0
    }
    ALooper::handler_id id() const {
        return mID;   //id()这个函数用于返回内部变量mID的值,其初始值为0,但是会通过setID函数设置
    }
    sp<ALooper> looper();
protected:
    virtual void onMessageReceived(const sp &msg) = 0;
private:
    friend struct ALooperRoster;
    ALooper::handler_id mID;
    //下面这个函数正式在其友元类ALooperRoster的registerHandler中调用的
    void setID(ALooper::handler_id id) {
        mID = id;
    }
};
ALooper::handler_id ALooperRoster::registerHandler(
        const sp looper, const sp &handler) {
    Mutex::Autolock autoLock(mLock);

    if (handler->id() != 0) {
        CHECK(!"A handler must only be registered once.");
        return INVALID_OPERATION;
    }
    HandlerInfo info;
    info.mLooper = looper;
    info.mHandler = handler;
    ALooper::handler_id handlerID = mNextHandlerID++;
    mHandlers.add(handlerID, info);
    handler->setID(handlerID);
    //针对每个handler调用registerHandler的时候都会设置一个独一无二的handler_id,最后发送消息进行处理的时候就是通过这个独一无二的handler_id这个变量找到处理handler类的。
    return handlerID;
}    

在这个函数中针对这个looper和handler会构造一个HandlerInfo结构体,然后放到pair容器中。一个looper可以有多个handler,但是一一个handler只能跟一个looper。

ALooper类

struct ALooper : public RefBase {
    typedef int32_t event_id;
    typedef int32_t handler_id;
    ALooper();
    // Takes effect in a subsequent call to start().
    void setName(const char *name);
    handler_id registerHandler(const sp &handler);
    void unregisterHandler(handler_id handlerID);
    status_t start(
            bool runOnCallingThread = false,
            bool canCallJava = false,
            int32_t priority = PRIORITY_DEFAULT
            );
private:
    friend struct ALooperRoster; 
    struct Event {
        int64_t mWhenUs;
        sp mMessage;
    };
   //后台存放事件的链表
    List<Event> mEventQueue;
    struct LooperThread;
    //后台处理线程
    sp<LooperThread> mThread;
    void post(const sp &msg, int64_t delayUs);
    bool loop();
};

ALooper 里面用Condition 做消息通知, List<Event>存储消息

能作为handler进行注册的类都必须是继承自AHandler这个类,注册的过程也是交给
gLooperRoster处理。

AMessage类:

消息类,用于构造消息,并通过post方法投递出去由ALooperRoster 类中转给ALooper

ALooperRoster类:中转类

将消息中转给ALooper 或者 AHandleReflector

ALooper

负责存储和转发AHandle的消息

LooperThread:

此线程循环调用ALooper的loop方法来转发消息

AHandleReflector类

消息处理类

使用方法
1.开始会创建一个ALooper对象, mLooper->start(...)

2.然后会实现一个AHandler的子类,
mLooper->registerhandler(objectXX)

子类实现一个onMessageReceived(XXXX),做收到消息的处理。

3.最后创建消息进行投递进入Message Queue。
创建AMessage里面,需要指定handleid,才能知道目标是发给谁。

mLooper(new ALooper)
mLooper->setName(name);  

mLooper->start(  
         false, // runOnCallingThread  
         false, // canCallJava  
         ANDROID_PRIORITY_FOREGROUND); 
mPlayer = new NUPlayer;
mLooper->registerHandler(mPlayer);  
//mPlayer是一个AHandler
mReflector =new AhandlerReflector<RTSPSource.(this);
mLooper->registerHandler(mReflector); 
(new AMessage(kWhatStart,id()))->post()
clipboard.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容