AHandler机制

来源:互联网 发布:蚁群算法基本步骤 编辑:程序博客网 时间:2024/06/06 01:02

AHandler机制

Android APP开发中为了不阻塞UI线程,利用handler,把UI线程分开异步执行,使用handler去执行某项比较费时的操作,然后异步更新UI线程。这部分是用Java来实现的,和传统Java的线程机制很类似。

流媒体(5.0中用的是NuPlayer)中也是类似的,因为联网,codec都很费时,需要异步执行。AHandler机制基于C++的实现,NuPlayer就是继承了AHandler,实际上就是用的AHandler。

对于handler消息机制,构成就必须包括一个Loop,message。那么对应的AHandler,也应该有对应的ALooper, AMessage。底层的多媒体框架NuPlayer中,都是用AHandler消息机制实现的。

结合Nuplayer的构造和媒体播放实现流程中的setDataSource来说明。

####1. NuPlayer构造
首先从NuplayerDriver的构造函数,这是流媒体(NuPlayer)播放初始化函数。代码位置:

frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cppclass NuPlayerFactory : public MediaPlayerFactory::IFactory {  public:    …    virtual sp<MediaPlayerBase> createPlayer() {        ALOGV(" create NuPlayer");        return new NuPlayerDriver;    }};// NuPlayerDriver中初始化的关键项NuPlayerDriver::NuPlayerDriver()    : mState(STATE_IDLE),      mIsAsyncPrepare(false),      mAsyncResult(UNKNOWN_ERROR),      mSetSurfaceInProgress(false),      mDurationUs(-1),      mPositionUs(-1),      mSeekInProgress(false),      mLooper(new ALooper), // 创建一个 ALooper      mPlayerFlags(0),      mAtEOS(false),      mLooping(false),      mAutoLoop(false),      mStartupSeekTimeUs(-1) {    ALOGV("NuPlayerDriver(%p)", this);    mLooper->setName("NuPlayerDriver Looper"); // 给该Looper取名字,以便与AHandler一一对应    mLooper->start( // 启动Looper            false, /* runOnCallingThread */            true,  /* canCallJava */            PRIORITY_AUDIO);     mPlayer = new NuPlayer; // 创建一个AHandler即Nuplayer    mLooper->registerHandler(mPlayer); // 把该AHandler注册到Looper中,具体的实现我们往后看    mPlayer->setDriver(this);}// 看到Looper就看成thread,ALooper的启动函数status_t ALooper::start(        bool runOnCallingThread, bool canCallJava, int32_t priority) {if (runOnCallingThread) {    …    }    Mutex::Autolock autoLock(mLock);    if (mThread != NULL || mRunningLocally) {        return INVALID_OPERATION;    }    mThread = new LooperThread(this, canCallJava); // 创建一个新的thread    status_t err = mThread->run(            mName.empty() ? "ALooper" : mName.c_str(), priority); // Thread运行    if (err != OK) {        mThread.clear();    }    return err;}// 注册handlerALooper::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; // NuPlayerDriver Looper    info.mHandler = handler; // NuPlayer    ALooper::handler_id handlerID = mNextHandlerID++;    mHandlers.add(handlerID, info); // 放进vector里    handler->setID(handlerID); // 设置handlerID,以便发送message时找到对应的handler    return handlerID;}ALooperRoster::ALooperRoster()    : mNextHandlerID(1), // 从一开始      mNextReplyID(1) {}

gLooperRoster是一个全局变量,并且是一个vector,以handler Id对应HandlerInfo,而HandlerInfo中包含的是一对Looper(就是thread)和handler。这样处理消息的时候,就以handler Id很快地找到对应的处理。

// Nuplayer本身也是个AHandler,因为其继承自AHandler。struct NuPlayer : public AHandler {NuPlayer();…}struct AHandler : public RefBase {    AHandler()        : mID(0) {    }    ALooper::handler_id id() const {        return mID;    }    sp<ALooper> looper();protected:    virtual void onMessageReceived(const sp<AMessage> &msg) = 0; // 处理消息private:    friend struct ALooperRoster;

有了LOOPER,也有了对应的handler,以setdataSource方法为例,很清晰地看到送消息给LOOPER,交个相应的handler去处理。

2. 以setDataSource看AHandler处理消息机制

这里写图片描述

void NuPlayer::setDataSourceAsync(        const sp<IMediaHTTPService> &httpService,        const char *url,        const KeyedVector<String8, String8> *headers) {    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); // 创建消息    size_t len = strlen(url);    sp<AMessage> notify = new AMessage(kWhatSourceNotify, id()); // 创建消息    sp<Source> source;    if (IsHTTPLiveURL(url)) {        source = new HTTPLiveSource(notify, httpService, url, headers);    } else if (!strncasecmp(url, "rtsp://", 7)) {        source = new RTSPSource(                notify, httpService, url, headers, mUIDValid, mUID);    } else if ((!strncasecmp(url, "http://", 7)                || !strncasecmp(url, "https://", 8))                    && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))                    || strstr(url, ".sdp?"))) {        source = new RTSPSource(                notify, httpService, url, headers, mUIDValid, mUID, true);    } else {        sp<GenericSource> genericSource =                new GenericSource(notify, mUIDValid, mUID);        // Don't set FLAG_SECURE on mSourceFlags here for widevine.        // The correct flags will be updated in Source::kWhatFlagsChanged        // handler when  GenericSource is prepared.        status_t err = genericSource->setDataSource(httpService, url, headers);        if (err == OK) {            source = genericSource;        } else {            ALOGE("Failed to set data source!");        }    }    msg->setObject("source", source);    msg->post();}

NuPlayer中的setDataSource主要做了这些事情:
1 创建相应的消息
2 根据URL创建对应的source
3 onmessageReceive处理对应的消息

首先新建一个AMessage的实例,传入的参数为事件的名称以及处理该消息的Handlerid,该id在mLooper->registerHandler(mPlayer);方法中设置上。

AMessage::AMessage(uint32_t what, ALooper::handler_id target)    : mWhat(what),      mTarget(target),      mNumItems(0) {}void AMessage::setObject(const char *name, const sp<RefBase> &obj) {    setObjectInternal(name, obj, kTypeObject);}void AMessage::setObjectInternal(        const char *name, const sp<RefBase> &obj, Type type) {    Item *item = allocateItem(name);    item->mType = type;    if (obj != NULL) { obj->incStrong(this); }    item->u.refValue = obj.get();}// post过程void AMessage::post(int64_t delayUs) {    gLooperRoster.postMessage(this, delayUs);}status_t ALooperRoster::postMessage(        const sp<AMessage> &msg, int64_t delayUs) {    sp<ALooper> looper = findLooper(msg->target()); // target及为获取handler id    if (looper == NULL) {        return -ENOENT;    }    looper->post(msg, 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); // 插入到event queue里}// 当队列里有消息时便会触发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());    }    gLooperRoster.deliverMessage(event.mMessage); // 处理消息    // 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;}void ALooperRoster::deliverMessage(const sp<AMessage> &msg) {    sp<AHandler> handler;    {        Mutex::Autolock autoLock(mLock);        ssize_t index = mHandlers.indexOfKey(msg->target());        if (index < 0) {            ALOGW("failed to deliver message. Target handler not registered.");            return;        }        const HandlerInfo &info = mHandlers.valueAt(index);        handler = info.mHandler.promote();        if (handler == NULL) {            ALOGW("failed to deliver message. "                 "Target handler %d registered, but object gone.",                 msg->target());            mHandlers.removeItemsAt(index);            return;        }    }    handler->onMessageReceived(msg); // 这里就回去调用NuPlayer}void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {switch (msg->what()) {        case kWhatSetDataSource:        {            ALOGV("kWhatSetDataSource");            CHECK(mSource == NULL);            status_t err = OK;            sp<RefBase> obj;            CHECK(msg->findObject("source", &obj));            if (obj != NULL) {                mSource = static_cast<Source *>(obj.get());            } else {                err = UNKNOWN_ERROR;            }            CHECK(mDriver != NULL);            sp<NuPlayerDriver> driver = mDriver.promote();            if (driver != NULL) {                driver->notifySetDataSourceCompleted(err);            }            break;        }    }}

Ahandler就是实现了异步机制,大致就是启动一个threadLooper,监听looper的消息队列是否有变化,如有交给相应的Handler去处理。
NuPlayer底层播放器所有 的实现依赖于这样的AHandler机制转动起来的。Android底层有很多类似的AHandler应用的地方,如在render中、获取m3u8 playlist的地方….

0 1