安卓异步消息处理机制ALooper
2017-03-03 10:32
309 查看
1.下面贴出安卓N版本ALooper.h的原文
#ifndef A_LOOPER_H_ #define A_LOOPER_H_ #include <media/stagefright/foundation/ABase.h> #include <media/stagefright/foundation/AString.h> #include <utils/Errors.h> #include <utils/KeyedVector.h> #include <utils/List.h> #include <utils/RefBase.h> #include <utils/threads.h> namespace android { struct AHandler; struct AMessage; struct AReplyToken; 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<AHandler> &handler); void unregisterHandler(handler_id handlerID); status_t start( bool runOnCallingThread = false, bool canCallJava = false, int32_t priority = PRIORITY_DEFAULT ); status_t stop(); static int64_t GetNowUs(); const char *getName() const { return mName.c_str(); } protected: virtual ~ALooper(); private: friend struct AMessage; // post() struct Event { int64_t mWhenUs; sp<AMessage> mMessage; }; Mutex mLock; Condition mQueueChangedCondition; AString mName; List<Event> mEventQueue; struct LooperThread; sp<LooperThread> mThread; bool mRunningLocally; // use a separate lock for reply handling, as it is always on another thread // use a central lock, however, to avoid creating a mutex for each reply Mutex mRepliesLock; Condition mRepliesCondition; // START --- methods used only by AMessage // posts a message on this looper with the given timeout void post(const sp<AMessage> &msg, int64_t delayUs); // creates a reply token to be used with this looper sp<AReplyToken> createReplyToken(); // waits for a response for the reply token. If status is OK, the response // is stored into the supplied variable. Otherwise, it is unchanged. status_t awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response); // posts a reply for a reply token. If the reply could be successfully posted, // it returns OK. Otherwise, it returns an error value. status_t postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &msg); // END --- methods used only by AMessage bool loop(); DISALLOW_EVIL_CONSTRUCTORS(ALooper); }; } // namespace android #endif // A_LOOPER_H_
1.1条件编译
#ifndef A_LOOPER_H_ #define A_LOOPER_H_ ... ... ... #endif // A_LOOPER_H_
条件编译宏,防止重复编译。
1.2包含的头文件
#include <media/stagefright/foundation/ABase.h> #include <media/stagefright/foundation/AString.h> #include <utils/Errors.h> #include <utils/KeyedVector.h> #include <utils/List.h> #include <utils/RefBase.h> #include <utils/threads.h>
1.3名字空间
namespace android { ... ... ... }
2.重要结构体struct Event
struct Event { int64_t mWhenUs; sp<AMessage> mMessage; }; List<Event> mEventQueue;
结构体struct Event有两个域,一个域是一个64bits的整数,是消息发送过来时给消息打的时间戳。
打的时间戳计算方法为:mWhenU=GetNowUs() + delayUs (delayUs > 0),即当用户设置的延时delayUs大于0的时候,给消息打的时间戳为系统时间(GetNowUs())加上用户设置的延时(delayUs)。
如果用户设置的延时delayUs小于等于0的时候,则直接采用系统时间(GetNowUs())给该消息打时间戳:whenUs = GetNowUs()
List< Event > mEventQueue,将所有发送来的消息打上时间戳后封装成事件都放到mEventQueue链表里,注意事件在链表里存放的顺序是按打的时间戳递增顺序来存放的。由于会频繁的向事件链表里插入事件,采用链式存储的表List是最合适的,因为插入和删除动作能在O(1)事件内完成。
3.ALooper::post函数的实现
下面贴出安卓N版本ALooper::post函数的实现void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) { Mutex::Autolock autoLock(mLock); int64_t whenUs; if (delayUs > 0) { whenUs = GetNowUs() + delayUs; } else { whenUs = GetNowUs(); } List<Event>::iterator it = mEventQueue.begin(); while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) { ++it; } Event event; event.mWhenUs = whenUs; event.mMessage = msg; if (it == mEventQueue.begin()) { mQueueChangedCondition.signal(); } mEventQueue.insert(it, event); }
4000
好了,前面介绍了ALooper的消息存储机制,现在来看下ALopper是如何设计外部接口来向事件链表里添加消息对应的事件的吧。
3.1给该消息计算时间戳
int64_t whenUs; if (delayUs > 0) { whenUs = GetNowUs() + delayUs; } else { whenUs = GetNowUs(); }
这个在前面已经讲到了,即根据delayUs的值来选择不同的计算时间戳的方法。
3.2计算该事件该插入的位置
List<Event>::iterator it = mEventQueue.begin(); while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) { ++it; }
这个很显然咯,就是从链表第一个位置,不停地迭代,直到找到第一个时间戳大于该事件的时间戳的位置it.然后将该事件插入到it的前面。这个很简单咯,但是真的很基础,数据结构链表的知识,就这样简单的迭代计算,大量地在安卓系统源码里用到。
3.3封装成事件
Event event; event.mWhenUs = whenUs; event.mMessage = msg;
就是分别用计算得到的时间戳,和消息的引用来填充Event结构体的两个域。来完成事件的封装。
3.4事件添加到链表里
mEventQueue.insert(it, event);
就是将该事件插入到it前面。it是之前计算得到的位置。
4.ALooper::loop函数的实现
下面贴出安卓N版本ALooper::loop函数实现源码:bool ALooper::loop() { Event event; { Mutex::Autolock autoLock(mLock); if (mThread == NULL && !mRunningLocally) { return false; } if (mEventQueue.empty()) { mQueueChangedCondition.wait(mLock); return true; } int64_t whenUs = (*mEventQueue.begin()).mWhenUs; int64_t nowUs = GetNowUs(); if (whenUs > nowUs) { int64_t delayUs = whenUs - nowUs; mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll); return true; } event = *mEventQueue.begin(); mEventQueue.erase(mEventQueue.begin()); } event.mMessage->deliver(); // NOTE: It's important to note that at this point our "ALooper" object // may no longer exist (its final reference may have gone away while // delivering the message). We have made sure, however, that loop() // won't be called again. return true; }
这个loop函数将被指定成函数入口,通过安卓系统实现的线程机制该入口函数将会不断地被调用。通俗的来说就是这个loop函数会不断低被执行,可以这样理解do { loop();} while(1);,但是真实的实现机制是比较复杂滴,后续的文章有机会的话会像大家介绍。
好了,这样就是建立了一个循环,在该循环里不断地将链表里第一个事件,也就是时间戳最小的事件,取出该事件,然后将该事件的消息派发出去。这样的设计很自然,因为时间戳越小说明该消息到达得越早,显然需要被优先处理。
4.1循环派发消息
int64_t whenUs = (*mEventQueue.begin()).mWhenUs; int64_t nowUs = GetNowUs(); if (whenUs > nowUs) { int64_t delayUs = whenUs - nowUs; mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll); return true; } event = *mEventQueue.begin(); mEventQueue.erase(mEventQueue.begin());
首先得到链表第一个事件的时间戳,然后得到当前系统的时间戳,如果事件的事件戳小于或者等于系统时间,说明该事件需要被派发出去不需要在链表里继续等待了。则跳过if (whenUs > nowUs)分支。
取出链表第一个事件,然后调用该事件消息的deliver()函数将该消息派发出去:
event.mMessage->deliver();
5.ALooper::registerHandler
下面贴出安卓N版本ALooper::registerHandler函数实现的源码:ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) { return gLooperRoster.registerHandler(this, handler); }
ALooper::registerHandler函数是通过调用全局对象gLooperRoster的registerHandler函数来实现的。当调用全局对象gLooperRoster的registerHandler函数,是传递的参数是,自身即消息链表的维护者(ALooper)引用和消息处理者(AHandler)。这样就将ALooper和AHandler绑定成一对儿来通过全局对象gLooperRoster的registerHandler函数来完成注册了。
相关文章推荐
- 安卓异步消息处理机制源码流程
- 安卓异步消息处理机制
- 安卓异步消息处理机制ALooperRoster
- 安卓UI线程与异步消息处理机制
- 安卓异步消息处理机制
- 安卓开发之异步消息处理机制
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解(Handler+Message处理机制)
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Handler+Message+MessageQuque+Looper 异步加载类 消息处理机制 分析
- android异步消息处理机制
- Android 异步消息处理机制(一) 让你深入理解 Looper、Handler、Message三者关系
- Android多线程----异步消息处理机制之Handler详解
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
- Android线程与异步消息处理机制