安卓异步消息处理机制源码流程
2017-03-03 13:44
537 查看
1.源码流程贴图
1.1源码例子部分代码贴图
NuPlayerDriver::NuPlayerDriver(pid_t pid) : mState(STATE_IDLE), mIsAsyncPrepare(false), mAsyncResult(UNKNOWN_ERROR), mSetSurfaceInProgress(false), mDurationUs(-1), mPositionUs(-1), mSeekInProgress(false), mLooper(new ALooper), mPlayerFlags(0), mAtEOS(false), mLooping(false), mAutoLoop(false) { ALOGV("NuPlayerDriver(%p)", this); mLooper->setName("NuPlayerDriver Looper"); mLooper->start( false, /* runOnCallingThread */ true, /* canCallJava */ PRIORITY_AUDIO); mPlayer = AVNuFactory::get()->createNuPlayer(pid); mLooper->registerHandler(mPlayer); mPlayer->setDriver(this); }
主要部分:
mLooper(new ALooper), mLooper->start( false, /* runOnCallingThread */ true, /* canCallJava */ PRIORITY_AUDIO); mLooper->registerHandler(mPlayer);
其中mLooper(new ALooper) 和mLooper->start创建一个线程,该线程不断地执行mLooper的loop函数,每执行一次loop函数就会从线程中由mLooper维护的事件链表取出首端事件,然后判断该事件的时间戳,如果该事件的时间戳小于或者等于当前系统的时间,则调用该事件消息的deliver函数将该事件的消息派发出去。
现在完成了这样一个创建,还没有向事件链表中添加任何事件。
下面贴出mLooper调用registerHandler函数的具体流程
==> mLooper->registerHandler(mPlayer); ==> ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) { return gLooperRoster.registerHandler(this, handler); } ==> ALooper::handler_id ALooperRoster::registerHandler( const sp<ALooper> looper, const sp<AHandler> &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, looper); return handlerID; } ==> handler->setID(handlerID, looper); ==> inline void setID(ALooper::handler_id id, wp<ALooper> looper) { mID = id; mLooper = looper; }
由ALooper调用其registerHandler函数来完成注册,整个注册过程除了将ALooper和AHandler绑定成一对儿,然后给予一个唯一的键值,存储在全局对象gLooperRoster的mHandlers容器中,还通过调用handler->setID(handlerID, looper)将这个键值和 looper的引用保存在handler中。
将键值和 looper的引用保存在handler中这很重要,因为只有拥有ALooper的引用,才能调用ALooper提供的post接口将事件添加到ALooper维护的事件链表中。
这样以来,一个经过注册的AHandler对象,将拥有一个非零的键值用来标识自己和与自己绑定在一起的ALooper对象,并且该AHandler对象含有该ALooper对象的引用,后续会通过这个引用来调用ALooper对象的post接口向ALooper对象维护的事件链表中。
1.2创建一个消息
==> void NuPlayer::start() { (new AMessage(kWhatStart, this))->post(); } ==> AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler) : mWhat(what), mNumItems(0) { setTarget(handler); } ==> void AMessage::setTarget(const sp<const AHandler> &handler) { if (handler == NULL) { mTarget = 0; mHandler.clear(); mLooper.clear(); } else { mTarget = handler->id(); mHandler = handler->getHandler(); mLooper = handler->getLooper(); } } ==> struct AHandler : public RefBase { wp<ALooper> getLooper() const { return mLooper; } wp<AHandler> getHandler() const { // allow getting a weak reference to a const handler return const_cast<AHandler *>(this); } };
创建消息的时候需要两个参数,一个是消息名,另一个是经过注册的消息处理者(AHandler),this这里是NuPlayer对象,也是前面的创建的mPlayer,是一个AHandler对象。
设置好了消息名后,然后调用setTarget(handler)函数,设置mTarget,mHandler,mLooper这些成员变量的值。其中mHandler和mLooper是一对儿经过注册的AHandler,ALooper对儿,mTarget是标识这一对儿的键值。
整个流程完成赋值后,形成的格局是:
有一对儿绑定在一起的AHandler,,ALooper跟据标识这一对儿的键值存储在全局对象gLooperRoster的mHandlers容器中。
然后这个经过注册的A
4000
Handler对象作为参数值来创建一个消息AMessage对象。这个AMessage对象通过传递的AHandler对象得到了这个AHandler对象的引用,并且获取到了他的handler ID 和ALooper对象的引用。
这样以来这个AMessage对象和AHandler对象都拥有了ALooper对象的引用引用,这样就可以通过调用ALooper对象的post函数来向ALooper对象维护的事件链表中添加事件。同时AMessage对象也拥有了AHandler对象的引用,这样就可以调用AHandler对象的函数来对该消息进行处理。
1.3发用消息
==> void NuPlayer::start() { (new AMessage(kWhatStart, this))->post(); } ==> status_t AMessage::post(int64_t delayUs) { sp<ALooper> looper = mLooper.promote(); if (looper == NULL) { ALOGW("failed to post message as target looper for handler %d is gone.", mTarget); return -ENOENT; } looper->post(this, delayUs); return OK; } ==> 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); }
通过调用该AMessage对象拥有的ALooper对象引用调用其post函数来向ALooper对象维护的事件链表添加消息。
1.4消息派发(deliver)
==> 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; } ==> event.mMessage->deliver(); ==> void AMessage::deliver() { sp<AHandler> handler = mHandler.promote(); if (handler == NULL) { ALOGW("failed to deliver message as target handler %d is gone.", mTarget); return; } handler->deliverMessage(this); }
通过AMessage对象拥有的AHandler对象的引用,然后调用AHandler对象对象的deliverMessage函数将消息派发出去。
1.5消息处理
==> handler->deliverMessage(this); ==> namespace android { void AHandler::deliverMessage(const sp<AMessage> &msg) { onMessageReceived(msg); mMessageCounter++; if (mVerboseStats) { uint32_t what = msg->what(); ssize_t idx = mMessages.indexOfKey(what); if (idx < 0) { mMessages.add(what, 1); } else { mMessages.editValueAt(idx)++; } } } } // namespace android ==> onMessageReceived(msg);
handler->deliverMessage函数里调用了onMessageReceived(msg);
onMessageReceived在AHandler里是纯虚函数,NuPlayer继承自AHandler并且重写了onMessageReceived。所以通过虚函数机制最终是在NuPlayer的onMessageReceived函数里对msg进行处理的
下面贴出安卓N版本AHandler.h的原文
#ifndef A_HANDLER_H_ #define A_HANDLER_H_ #include <media/stagefright/foundation/ALooper.h> #include <utils/KeyedVector.h> #include <utils/RefBase.h> namespace android { struct AMessage; struct AHandler : public RefBase { AHandler() : mID(0), mVerboseStats(false), mMessageCounter(0) { } ALooper::handler_id id() const { return mID; } sp<ALooper> looper() const { return mLooper.promote(); } wp<ALooper> getLooper() const { return mLooper; } wp<AHandler> getHandler() const { // allow getting a weak reference to a const handler return const_cast<AHandler *>(this); } protected: virtual void onMessageReceived(const sp<AMessage> &msg) = 0; private: friend struct AMessage; // deliverMessage() friend struct ALooperRoster; // setID() ALooper::handler_id mID; wp<ALooper> mLooper; inline void setID(ALooper::handler_id id, wp<ALooper> looper) { mID = id; mLooper = looper; } bool mVerboseStats; uint32_t mMessageCounter; KeyedVector<uint32_t, uint32_t> mMessages; void deliverMessage(const sp<AMessage> &msg); DISALLOW_EVIL_CONSTRUCTORS(AHandler); }; } // namespace android #endif // A_HANDLER_H_
2.总结
整体来说安卓N版本里异步消息处理机制较安卓M版本有了很大的变化,不过涉及到的还是ALooper,AHandler,AMessage这三个。只不过在实现机理上有了不小的变化。我觉得N版本这个实现机理上还是比较好的,但是容易绕糊涂。
对这个版本的实现机理做个小结:
ALooper提供post函数用来向事件链表里添加消息,AHandler提供函数deliverMessage来完成消息派发。两个函数调用都是发生在AMessage提供的post和deliver函数里的。因此问题的关键就是这个中间者需要拥有ALooper,AHandler的引用这样就可以在自己的post和deliver函数里里分被调用ALooper提供的post函数和AHandler提供函数deliverMessage来完成事件的添加和消息的派发。
相关文章推荐
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- 【转】Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android异步消息处理机制(2)源码解析
- Android异步消息处理机制详解及源码分析
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- 【转】Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android异步消息处理机制完全解析(源码角度)
- 安卓UI线程与异步消息处理机制
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解(Handler+Message处理机制)
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android异步消息处理机制(二):从源码的角度彻底理解
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android消息处理机制:源码剖析Handler、Looper,并实现图片异步加载