【android12】【AHandler】【4.AHandler原理篇ALooper类方法全解】

AHandler系列

【android12】【AHandler】【1.AHandler异步无回复消息原理篇】-CSDN博客

【android12】【AHandler】【2.AHandler异步回复消息原理篇】-CSDN博客

【android12】【AHandler】【3.AHandler原理篇AHandler类方法全解】-CSDN博客

其他系列

本人系列文章-CSDN博客


1.简介

前面我们主要介绍了有回复和无回复的消息的使用方法和源码解析,为了更好的理解Ahandler这个类的作用,本篇便主要对AHandler类的所有方法进行全解。

简单介绍一下Ahandler机制

AHandler是Android native层实现的一个异步消息机制,在这个机制中所有的处理都是异步的,将消息封装到一个消息AMessage结构体中,然后放到消息队列中去,后台专门有一个线程ALooper会从这个队列中取出消息然后分发执行,执行函数就是AHandler实例的onMessageReceived。

在AHandler中的消息分为不需要回复的消息和需要回复的消息。

不需要回复的消息:当被post到消息队列后,Alooper会从消息队列中取出消息,并发送给相应的Ahandler的onMessageReceived进行处理。

需要回复的消息:当被post到消息队列后,Alooper会从消息队列中取出消息,并发送给相应的Ahandler的onMessageReceived进行处理,处理完后,Ahandler会将想回复的消息返回给发送方,发送方接受返回的response消息。

1.1 主要类及其作用

AHandler:处理类,用于消息的处理,有一个纯虚函数onMessageReceived,一般需要继承此类并重写此方法,用于接受和处理消息。

AMessage:消息类,用于构建各种消息,通过post方法将消息发送给Alooper

Alooper:轮询类,用于保存消息队列,然后将消息发送到对应的AHandler

AReplyToken:这类似一个标识,表示要回复的是哪一条消息

 1.2 Alooper类图

2.源码解析

2.1 Alooper类

//Alooper.h分析
struct ALooper : public RefBase {typedef int32_t event_id;typedef int32_t handler_id;ALooper();void setName(const char *name);//设置looper的名称handler_id registerHandler(const sp<AHandler> &handler);//注册Handler,用map保存hadnler_id和handler信息void unregisterHandler(handler_id handlerID);//取消注册handlerstatus_t start(bool runOnCallingThread = false,bool canCallJava = false,int32_t priority = PRIORITY_DEFAULT);//让Alooper线程运行起来status_t stop();//让Alooer线程停止运行static int64_t GetNowUs();//获取当前时间const char *getName() const {//获取当前Alooper的名称return mName.c_str();}protected:virtual ~ALooper();//虚析构private:friend struct AMessage;//友元结构体struct Event {int64_t mWhenUs;sp<AMessage> mMessage;};//存储Amessage的消息。Mutex mLock;//锁Condition mQueueChangedCondition;//条件变量,用于唤醒线程AString mName;//Alooper的名称List<Event> mEventQueue;//消息队列,会根据等待时间来从小到大排序struct LooperThread;//此处是声明。sp<LooperThread> mThread;//智能指针指向LooperThreadbool mRunningLocally;//线程是否在运行//使用单独的锁进行回复的处理,因为它总是在另一个线程上。但是,使用中心锁可以避免为每个回复创建mutex Mutex mRepliesLock;Condition mRepliesCondition;//发送一个消息到Aloope中void post(const sp<AMessage> &msg, int64_t delayUs);// 创建一个和当前looper一起使用的AReplyToken,AReplyToken主要用于回复消息sp<AReplyToken> createReplyToken();//发送方用于等待回复的消息status_t awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response);//接收方向发送方回复消息status_t postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &msg);bool loop();//死循环,不断的从消息队列中取出消息。DISALLOW_EVIL_CONSTRUCTORS(ALooper);
};

2.2 ALooper::GetNowUs

// static
int64_t ALooper::GetNowUs() {//获取当前时间return systemTime(SYSTEM_TIME_MONOTONIC) 
}

2.3 ALooper::ALooper构造函数

会清除旧的Ahandler

ALooper::ALooper(): mRunningLocally(false) {gLooperRoster.unregisterStaleHandlers();//清除旧的Ahandler。从保存注册Ahandler的列表中删除
}

2.4 析构函数

调用stop函数,让looper线程停止循环,并释放线程资源

ALooper::~ALooper() {stop();
}

2.5 ALooper::setName

void ALooper::setName(const char *name) {//为looper设置名称mName = name;
}

2.6 ALooper::registerHandler

注册Ahandler并将其保存到一个容器中。

ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {//注册Ahandler,用一个map保存alooper和Ahandler的对应关系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) {//此时handler->id()等于0CHECK(!"A handler must only be registered once.");return INVALID_OPERATION;}HandlerInfo info;//定义是struct HandlerInfo {//wp<ALooper> mLooper;//wp<AHandler> mHandler;//};info.mLooper = looper;//赋值looperinfo.mHandler = handler;//赋值handlerALooper::handler_id handlerID = mNextHandlerID++;//mNextHandlerID在构造函数是1,此时handler_id值是1,mNextHandlerID变为2mHandlers.add(handlerID, info);//保存信息KeyedVector<ALooper::handler_id, HandlerInfo> mHandlers;handler->setID(handlerID, looper);//此时handlerID等于1,handler持有looper的弱引用return handlerID;
}

2.7 ALooper::unregisterHandler

取消注册Ahandler,从容器中删除此Ahandler

void ALooper::unregisterHandler(handler_id handlerID) {//取消注册handlergLooperRoster.unregisterHandler(handlerID);
}
void ALooperRoster::unregisterHandler(ALooper::handler_id handlerID) {Mutex::Autolock autoLock(mLock);ssize_t index = mHandlers.indexOfKey(handlerID);//获取handlerID对应的位置if (index < 0) {return;}const HandlerInfo &info = mHandlers.valueAt(index);sp<AHandler> handler = info.mHandler.promote();if (handler != NULL) {//如果handler存在,则设置其id为0handler->setID(0, NULL);}mHandlers.removeItemsAt(index);//移除此handler
}

2.8 ALooper::start

主要作用为:

1.创建了一个LooperThread类对象,此类对象会创建一个线程

2.让线程运行起来。

//如果runOnCallingThread表示,是否开启新的线程
//如果runOnCallingThread = true:那么当前线程不会再做其它工作,陷入一个死循环。用于循环执行loop()函数。
//如果runOnCallingThread = false:会创建一个子线程,并将loop()逻辑放到这个特定子线程中处理。
status_t start(bool runOnCallingThread = false,bool canCallJava = false,int32_t priority = PRIORITY_DEFAULT);
status_t ALooper::start(bool runOnCallingThread, bool canCallJava, int32_t priority) {//传入的runOnCallingThread=false,canCallJava=false,priority优先级PRIORITY_DEFAULTif (runOnCallingThread) {//如果不创建新的线程,则当前线程死循环调用loop{Mutex::Autolock autoLock(mLock);if (mThread != NULL || mRunningLocally) {return INVALID_OPERATION;}mrunninglocally = true;//mrunninglocally 为true意味着当前线程陷入loop的死循环}do {} while (loop());return ok;}Mutex::Autolock autoLock(mLock);if (mThread != NULL || mRunningLocally) {//此时mThread为空return INVALID_OPERATION;//无效操作}mThread = new LooperThread(this, canCallJava);//this是ALooper指针对象,canCallJava是false,new了一个继承自Thread的类status_t err = mThread->run(mName.empty() ? "ALooper" : mName.c_str(), priority);//让线程跑起来。传递的参数应该是ALooper,priority为PRIORITY_DEFAULT//线程的threadLoop方法会执行if (err != OK) {mThread.clear();}return err;
}

此函数的后续流程如下:

 2.8.1 LooperThread 构造函数

struct ALooper::LooperThread : public Thread {LooperThread(ALooper *looper, bool canCallJava): Thread(canCallJava),mLooper(looper),mThreadId(NULL) {}
//this是ALooper指针对象,canCallJava是false
}

 2.8.2  LooperThread构造函数

struct ALooper::LooperThread : public Thread {LooperThread(ALooper *looper, bool canCallJava): Thread(canCallJava),mLooper(looper),mThreadId(NULL) {}
//this是ALooper指针对象,canCallJava是false
}

2.8.3 Thread构造函数

Thread::Thread(bool canCallJava): mCanCallJava(canCallJava),//canCallJava此时传入的是falsemThread(thread_id_t(-1)),//定义类型是thread_id_t mThread;,代表线程id,//typedef android_thread_id_t thread_id_t;typedef void* android_thread_id_t;所以android_thread_id_t是一个void*的指针。mLock("Thread::mLock"),//互斥量mStatus(OK),mExitPending(false),mRunning(false)//表示此线程是否正在运行
#if defined(__ANDROID__),mTid(-1)
#endif
{
}

2.8.4 Thread::run

主要作用为:

1.调用androidCreateRawThreadEtc方法,此方法通过pthread创建了一个线程,并使线程分离,并执行_threadLoop方法

status_t Thread::run(const char* name, int32_t priority, size_t stack)
//此时传入的参数是name = Alooper,
//stack默认是0,priority为PRIORITY_DEFAULT
{Mutex::Autolock _l(mLock);/*if (mRunning) {//此时为false// thread already startedreturn INVALID_OPERATION;//表示线程已经start}
*///重置status和exitPending为其默认值,mStatus = OK;mExitPending = false;mThread = thread_id_t(-1);//持有自己的强引用mHoldSelf = this;//定义是sp<Thread>  mHoldSelf; this 是当前mThread线程对象mRunning = true;bool res;if (mCanCallJava) {//此时是falseres = createThreadEtc(_threadLoop,this, name, priority, stack, &mThread);} else {res = androidCreateRawThreadEtc(_threadLoop,this, name, priority, stack, &mThread);//此处的作用是通过pthread创建了一个线程,并使线程分离,并执行_threadLoop方法}// if (res == false) {//线程创建出错,正常不执行// mStatus = UNKNOWN_ERROR;   // something happened!// mRunning = false;// mThread = thread_id_t(-1);// mHoldSelf.clear();  // "this" may have gone away after this.// return UNKNOWN_ERROR;// }return OK;
}

2.8.5 androidCreateRawThreadEtc

主要作用为:

1.通过pthread_create创建一个分离的线程,并执行_threadLoop方法

int androidCreateRawThreadEtc(android_thread_func_t entryFunction,void *userData,const char* threadName __android_unused,int32_t threadPriority,size_t threadStackSize,android_thread_id_t *threadId)//entryFunction是_threadLoop函数,android_thread_func_t是一个函数指针//定义是typedef int (*android_thread_func_t)(void*);//userData是Thread的类的指针的对象//__android_unused是Alooper//threadPriority为PRIORITY_DEFAULT//threadStackSize是0//threadId = -1
{pthread_attr_t attr;//创建线程属性变量pthread_attr_init(&attr);//初始化线程属性pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);设置线程属性是否分离。PTHREAD_CREATE_DETACHED为分离#if defined(__ANDROID__)  /* valgrind is rejecting RT-priority create reqs */
/*if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {//如果线程不是默认优先级// Now that the pthread_t has a method to find the associated// android_thread_id_t (pid) from pthread_t, it would be possible to avoid// this trampoline in some cases as the parent could set the properties// for the child.  However, there would be a race condition because the// child becomes ready immediately, and it doesn't work for the name.// prctl(PR_SET_NAME) only works for self; prctl(PR_SET_THREAD_NAME) was// proposed but not yet accepted.thread_data_t* t = new thread_data_t;t->priority = threadPriority;t->threadName = threadName ? strdup(threadName) : NULL;t->entryFunction = entryFunction;t->userData = userData;entryFunction = (android_thread_func_t)&thread_data_t::trampoline;userData = t;}*/
#endif// if (threadStackSize) {//此时是0,不设置// pthread_attr_setstacksize(&attr, threadStackSize);//设置线程属性中线程栈的大小// }errno = 0;pthread_t thread;int result = pthread_create(&thread, &attr,(android_pthread_entry)entryFunction, userData);//attr是线程属性。//entryFunction是线程要执行的函数_threadLoop,userData是Thread的强引用对象pthread_attr_destroy(&attr);//创建线程完成后,可以销毁属性。if (result != 0) {ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, %s)\n""(android threadPriority=%d)",entryFunction, result, strerror(errno), threadPriority);return 0;}// Note that *threadID is directly available to the parent only, as it is// assigned after the child starts.  Use memory barrier / lock if the child// or other threads also need access.if (threadId != nullptr) {*threadId = (android_thread_id_t)thread; // XXX: this is not portable}return 1;
}

2.8.6 _threadLoop

主要作用为:

1.死循环调用继承类的threadLoop方法,当threadLoop方法返回true并且没有调用requsetexit函数时,会一直循环的调用threadLoop函数

int Thread::_threadLoop(void* user)//此处传入的是Thread强引用对象
{Thread* const self = static_cast<Thread*>(user);//将void*类的指针转化为Thread*sp<Thread> strong(self->mHoldSelf);//获取Thread的强引用,此处是self->mHoldSelf是sp类型,故此处是拷贝构造,指向的对象引用会是2wp<Thread> weak(strong);//获取弱引用self->mHoldSelf.clear();//让强引用减一#if defined(__ANDROID__)// this is very useful for debugging with gdbself->mTid = gettid();
#endifbool first = true;do {bool result;if (first) {//如果是第一次运行线程。first = false;self->mStatus = self->readyToRun();//此处就是返回一个okresult = (self->mStatus == OK);if (result && !self->exitPending()) {result = self->threadLoop();//此处函数是虚函数,需要类去继承。调用的是子类的threadLooper函数。//在此处是struct ALooper::LooperThread : public Thread类的threadLoop方法}} else {result = self->threadLoop();//此处函数是虚函数,需要类去继承。调用的是子类的threadLooper函数。//在此处是struct ALooper::LooperThread : public Thread类的threadLoop方法}// establish a scope for mLock{Mutex::Autolock _l(self->mLock);if (result == false || self->mExitPending) {//一般result都是true,self->mExitPending默认是false,//表示是否退出,在requestExit函数和requestExitAndWait函数中会设置为trueself->mExitPending = true;self->mRunning = false;// clear thread ID so that requestExitAndWait() does not exit if// called by a new thread using the same thread ID as this one.//清除线程IDself->mThread = thread_id_t(-1);// note that interested observers blocked in requestExitAndWait are// awoken by broadcast, but blocked on mLock until break exits scopeself->mThreadExitedCondition.broadcast();//mThreadExitedCondition是Condition类对象。//底层调用了pthread_cond_broadcast,唤醒所有在此conditon等待的线程break;}}// Release our strong reference, to let a chance to the thread// to die a peaceful death.strong.clear();//短暂的让强指针引用-1,以便有机会让线程释放。// And immediately, re-acquire a strong reference for the next loopstrong = weak.promote();//立即获取强引用} while(strong != nullptr);//死循环return 0;
}

2.8.7 LooperThread::threadLoop

//线程调用run方法后,会调用threadLoop方法,当其返回true并且没有调用requsetexit函数时,会一直循环的调用threadLoop函数
struct ALooper::LooperThread : public Thread {
virtual bool threadLoop() {return mLooper->loop();}
}

2.8.8 ALooper::loop

此函数后续仍会遇见,我们现在只介绍当前的作用。

此时,looper刚启动,所以其消息队列中的消息为空,故此时是线程在条件变量上进行了等待。

当另外一个线程生成AMessage消息,并post时,会将此消息post到消息队列中,然后唤醒此looper线程,此时消息队列存在消息,会取出消息,并执行deliver函数去运输消息,最后会执行此消息。

bool ALooper::loop() {Event event;//event结构体为//struct Event {//int64_t mWhenUs;//sp<AMessage> mMessage;//};{Mutex::Autolock autoLock(mLock);if (mThread == NULL && !mRunningLocally) {//此时mThread不为空,mRunningLocally值为flasereturn false;}if (mEventQueue.empty()) {//此时消息队列应该是空的mQueueChangedCondition.wait(mLock);//此处定义是Condition mQueueChangedCondition;此线程阻塞在这里等待。//调用的是inline status_t Condition::wait(Mutex& mutex) {return -pthread_cond_wait(&mCond, &mutex.mMutex);}return true;//后面暂时不执行// }// int64_t whenUs = (*mEventQueue.begin()).mWhenUs;// int64_t nowUs = GetNowUs();// if (whenUs > nowUs) {// int64_t delayUs = whenUs - nowUs;// if (delayUs > INT64_MAX / 1000) {// delayUs = INT64_MAX / 1000;// }// 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;
}
}
}

2.9 ALooper::stop

 此函数内部主要会调用调用requestExit方法。此方法会将一个线程循环的flag标志设置为true,等到下一次线程循环的时候,线程便会退出循环,然后释放线程资源。

status_t ALooper::stop() {sp<LooperThread> thread;bool runningLocally;{Mutex::Autolock autoLock(mLock);thread = mThread;//拷贝构造,使得强引用计数+1了runningLocally = mRunningLocally;mThread.clear();//强引用计数减1mRunningLocally = false;}if (thread == NULL && !runningLocally) {return INVALID_OPERATION;}if (thread != NULL) {//停止线程thread->requestExit();//调用requestExit方法。查看Thread类的结构可知,mExitPending = true会设置为true}
.mQueueChangedCondition.signal();//通知信号量等待的线程。然后会结束死循环。线程分离会自动销毁。{Mutex::Autolock autoLock(mRepliesLock);mRepliesCondition.broadcast();//广播唤醒在mRepliesCondition等待的所有线程}if (!runningLocally && !thread->isCurrentThread()) {// If not running locally and this thread _is_ the looper thread,// the loop() function will return and never be called again.//如果不是在本地运行,并且此线程_is_为looper线程,则loop()函数将返回并且不再被调用。thread->requestExitAndWait();}return OK;
}

此函数的后续流程为:

2.9.1 Thread::requestExit

设置mExitPending的标志位为true,线程就会退出循环,然后释放线程资源

//requestExit() 请求退出线程,立即返回。
void Thread::requestExit()
{Mutex::Autolock _l(mLock);mExitPending = true;//设置mExitPending的值为true,此时_threadLoop会执行下面的代码块。然后退出循环。然后由于线程是分离的,_threadLoop函数执行完,会自动回收。
}

 2.9.2 Thread::requestExitAndWait

当我们调用stop的时候是在A线程中,当我们设置mExitPending为ture后,表示要释放之前创建的分离的looper线程,而此时A线程需要等待looper线程释放完相关资源后,再往下走。

status_t Thread::requestExitAndWait()
{Mutex::Autolock _l(mLock);if (mThread == getThreadId()) {//如果是之前使用当前线程作为处理消息的线程,而不是新创建了一个线程。//那么此时自己调用requestExitAndWait,需要返回,不需要在下面mThreadExitedCondition条件变量上进行等待,因为只有一个线程,//此时线程会一直等待,因为没有其他线程唤醒。ALOGW("Thread (this=%p): don't call waitForExit() from this ""Thread object's thread. It's a guaranteed deadlock!",this);return WOULD_BLOCK;}mExitPending = true;while (mRunning == true) {mThreadExitedCondition.wait(mLock);}// This next line is probably not needed any more, but is being left for// historical reference. Note that each interested party will clear flag.mExitPending = false;return mStatus;
}

2.9.3 _threadLoop

此时我们需要回到looper线程的这个函数,此时self->mExitPending为ture,然后当前线程会退出死循环,清除线程的id,同时唤醒之前等待的A线程。由于是分离的线程,故此时分离的线程会自动释放资源。

int Thread::_threadLoop(void* user)//此处传入的是Thread强引用对象
{Thread* const self = static_cast<Thread*>(user);//将void*类的指针转化为Thread*sp<Thread> strong(self->mHoldSelf);//获取Thread的强引用,此处是self->mHoldSelf是sp类型,故此处是拷贝构造,指向的对象引用会是2wp<Thread> weak(strong);//获取弱引用self->mHoldSelf.clear();//让强引用减一#if defined(__ANDROID__)// this is very useful for debugging with gdbself->mTid = gettid();
#endifbool first = true;do {bool result;if (first) {//如果是第一次运行线程。first = false;self->mStatus = self->readyToRun();//此处就是返回一个okresult = (self->mStatus == OK);if (result && !self->exitPending()) {result = self->threadLoop();//此处函数是虚函数,需要类去继承。调用的是子类的threadLooper函数。//在此处是struct ALooper::LooperThread : public Thread类的threadLoop方法}} else {result = self->threadLoop();//此处函数是虚函数,需要类去继承。调用的是子类的threadLooper函数。//在此处是struct ALooper::LooperThread : public Thread类的threadLoop方法}// establish a scope for mLock{Mutex::Autolock _l(self->mLock);if (result == false || self->mExitPending) {//一般result都是true,self->mExitPending默认是false,//表示是否退出,在requestExit函数和requestExitAndWait函数中会设置为trueself->mExitPending = true;self->mRunning = false;// clear thread ID so that requestExitAndWait() does not exit if// called by a new thread using the same thread ID as this one.//清除线程IDself->mThread = thread_id_t(-1);// note that interested observers blocked in requestExitAndWait are// awoken by broadcast, but blocked on mLock until break exits scopeself->mThreadExitedCondition.broadcast();//mThreadExitedCondition是Condition类对象。//底层调用了pthread_cond_broadcast,唤醒所有在此conditon等待的线程break;}}// Release our strong reference, to let a chance to the thread// to die a peaceful death.strong.clear();//短暂的让强指针引用-1,以便有机会让线程释放。// And immediately, re-acquire a strong reference for the next loopstrong = weak.promote();//立即获取强引用} while(strong != nullptr);//死循环return 0;
}

2.10 ALooper::post

主要作用为:

1.将消息根据时延大小放到消息队列的指定位置,然后唤醒Alooper线程。

void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {Mutex::Autolock autoLock(mLock);int64_t whenUs;if (delayUs > 0) {//表示是否延时发送int64_t nowUs = GetNowUs();whenUs = (delayUs > INT64_MAX - nowUs ? INT64_MAX : nowUs + 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;//生成eventif (it == mEventQueue.begin()) {//如果当前消息应该插入到消息队列的队首mQueueChangedCondition.signal();//则使用条件遍历唤醒线程}mEventQueue.insert(it, event);//插入该event到指定位置
}

2.11 ALooper::loop

主要作用为:

1.从消息队列中取出消息,然后将消息发送到指定的Ahandler处理者去处理此消息。

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;//获取消息队列的位于头部的event的时延,因为位于头部的event是时延最小的消息int64_t nowUs = GetNowUs();if (whenUs > nowUs) {//如果时延大于当前时间,意味着时间还没到。int64_t delayUs = whenUs - nowUs;if (delayUs > INT64_MAX / 1000) {delayUs = INT64_MAX / 1000;}mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);//因为位于头部的event是时延最小的消息,所以此时需要等待时间到达,时间到达后,返回true,然后开启下一次循环return true;}event = *mEventQueue.begin();//取出头部的event事件mEventQueue.erase(mEventQueue.begin());//将此evnet从消息队列中删除}event.mMessage->deliver();//调用Amessage的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;
}

2.12 ALooper::createReplyToken

主要作用为:

1.创建一个AReplyToken对象,用于表示是哪个消息需要回复。

sp<AReplyToken> ALooper::createReplyToken() {//此时A线程发送消息,然后阻塞等待B线程发送回复消息。
//然后b线程收到消息后,发送消息到A线程。在这个流程中,AReplyToken在A线程的发送消息的时候被创建,然后保存该回复令牌到发送消息内部。
//当发送的消息到达B线程后,b线程会取出此回复令牌,然后将回复的消息,设置进此AReplyToken对象中,由于A线程也持有此对象,故A线程会死循环的拿回复的消息。return new AReplyToken(this);
}

2.13 ALooper::awaitResponse

死循环取回回复,到response中。取回后返回ok,未取回,则一直wait等待阻塞。

status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) {// return status in case we want to handle an interrupted waitMutex::Autolock autoLock(mRepliesLock);CHECK(replyToken != NULL);while (!replyToken->retrieveReply(response)) {//死循环取回回复,到response中。取回后返回ok,未取回,则一直wait等待阻塞。{Mutex::Autolock autoLock(mLock);if (mThread == NULL) {return -ENOENT;}}mRepliesCondition.wait(mRepliesLock);}return OK;
}

2.14 ALooper::postReply

1.将接收方Ahandler回复的Amessage设置到replyToken对象中。

2.唤醒发送方wait之前wait阻塞的地方。

status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) {Mutex::Autolock autoLock(mRepliesLock);status_t err = replyToken->setReply(reply);//将此回复消息reply设置到replyToken中if (err == OK) {mRepliesCondition.broadcast();//广播之前mRepliesCondition.wait(mRepliesLock)的地方。}return err;
}

 将Amessage消息保存到AReplyToken类对象中。

status_t AReplyToken::setReply(const sp<AMessage> &reply) {if (mReplied) {ALOGE("trying to post a duplicate reply");return -EBUSY;}CHECK(mReply == NULL);mReply = reply;//将传入的Amessage消息保存到AReplyToken中mReplied = true;return OK;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/58907.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SSM志愿者招募系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;志愿组织管理&#xff0c;组织信息管理&#xff0c;组织申请管理&#xff0c;志愿活动管理活动报名管理 用户账号功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;…

selinux介绍和Linux中的防火墙

selinux 1、selinux的说明 2、selinux的工作原理 3、selinux的启动、关闭与查看 防火墙 1、什么是防火墙 2、iptables &#xff08;1&#xff09;iptables介绍 参数说明 3、firewalld firewalld-cmd的参数说明

RHCE4

一、web服务器简介 1、什么是www www 是 world wide web 的缩写&#xff0c;也就是全球信息广播的意思。通常说的上网就是使用 www 来查询用户所需要的信息。 www 可以结合文字、图形、影像以及声音等多媒体&#xff0c;并通过可以让鼠标单击超链接的方式将信息以 Internet 传…

推荐一款用来快速开发3D建筑模型软件:Allplan

Nemetschek Allplan是一款用来快速开发3D建筑模型软件的软件&#xff0c;它的简单好用但是功能强大&#xff0c;绝对不输AuToDesk&#xff0c;而且人性化的设计更让你可以快速的建立开发及维护你的建筑模型。是与ArchiCAD称兄道弟的强大建筑设计软件&#xff0c;功能上互有短长…

Python面向对象,实现图片处理案例,支持:高斯模糊、Canny边缘检测、反转边缘图像、生成手绘效果、调亮度......等等

实验图片如下&#xff1a; 命名为img1.jpg, 放在项目下新建文件夹images下 项目构造如下&#xff1a; app.py源码如下 import cv2 import os from matplotlib import pyplot as plt import numpy as npclass ImageProcessor:def __init__(self, image_path):self.image cv…

利用LangChain与LLM打造个性化私有文档搜索系统

我们知道LLM&#xff08;大语言模型&#xff09;的底模是基于已经过期的公开数据训练出来的&#xff0c;对于新的知识或者私有化的数据LLM一般无法作答&#xff0c;此时LLM会出现“幻觉”。针对“幻觉”问题&#xff0c;一般的解决方案是采用RAG做检索增强。 但是我们不可能把…

C++ 基础语法 一

C 基础语法 一 文章目录 C 基础语法 一const 限定符常量指针类型别名autodecltypeQStringvector迭代器指针和数组显示转换static_castconst_cast 函数尽量使用常量引用数组形参不要返回局部对象的引用和指针返回数组指针 C四种转换内联函数constexpr函数函数指针 const 限定符 …

tensorflow案例4--人脸识别(损失函数选取,调用VGG16模型以及改进写法)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 这个模型结构算上之前的pytorch版本的&#xff0c;算是花了不少时间&#xff0c;但是效果一直没有达到理想情况&#xff0c;主要是验证集和训练集准确率…

力扣每日一题 超级饮料的最大强化能量 动态规划(dp)

来自未来的体育科学家给你两个整数数组 energyDrinkA 和 energyDrinkB&#xff0c;数组长度都等于 n。这两个数组分别代表 A、B 两种不同能量饮料每小时所能提供的强化能量。 你需要每小时饮用一种能量饮料来 最大化 你的总强化能量。然而&#xff0c;如果从一种能量饮料切换到…

全国产 V7 690T+FT6678 高性能实时信号处理平台设计原理

1、概述 全国产 V7 690TFT6678 高性能实时信号处理平台组成如图 1 所示&#xff0c;包含 1 片SMQ7VX690TFFG1761 和两片 FT-6678&#xff08;国防科大&#xff09;的 DSP&#xff0c;总共 3 个主芯片&#xff1b;每个主芯片外部各搭配 1 组 64bit 的 DDR3 内存模组以及各芯片启…

0.STM32F1移植到F0的各种经验总结

1.结构体的声明需放在函数的最前面 源代码&#xff1a; /*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //开启USART1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructu…

Linux高阶——1027—守护进程

1、守护进程的基本流程 1、父进程创建子进程&#xff0c;父进程退出 守护进程是孤儿进程&#xff0c;但是是工程师人为创建的孤儿进程&#xff0c;低开销模式运行&#xff0c;对系统没有压力 2、子进程&#xff08;守护进程&#xff09;脱离控制终端&#xff0c;创建新会话 …

Selective Generation for Language Models 语言模型的选择性生成

生成式语言模型&#xff08;Generative Language Models, GLMs&#xff09;在文本生成任务中取得了显著进展。然而&#xff0c;生成内容的“幻觉”现象&#xff0c;即生成内容与事实或真实语义不符的问题&#xff0c;仍是GLMs在实际应用中的一个重大挑战。为了解决这一问题&…

-bash: ./my_rename.sh: /bin/bash^M: bad interpreter: No such file or directory

在windows上写了一个shell脚本&#xff0c;在Linux上执行时报错&#xff0c;然后看下解决办法&#xff1a; 查了下&#xff0c;其实就是windows系统里文件行尾的换行符和Linux不同引起的&#xff0c; sed -i s/\r$// my.sh用这行代码处理一下&#xff0c;就可以正常运行了。 执…

flutter区别于vue的写法

View.dart 页面渲染&#xff1a; 类似于vue里面使用 <template> <div> <span> <textarea>等标签绘制页面, flutter 里面则是使用不同的控件来绘制页面 样式 与传统vue不同的是 flutter里面没有css/scss样式表&#xff0c; Flutter的理念是万物皆…

idea免费安装步骤,(java集成开发环境)超详细

第一步 点击链接下载 百度网盘 请输入提取码 提取码是idea 下载步骤 可设也可不设置 我就没有设置 下一步 就点击安装就大功告成了

SAP RFC 用户安全授权

一、SAP 通讯用户 对于RFC接口的用户&#xff0c;使用五种用户类型之一的“通讯”类型&#xff0c;这种类型的用户没有登陆SAPGUI的权限。 二、对调用的RFC授权 在通讯用户内部&#xff0c;权限对象&#xff1a;S_RFC中&#xff0c;限制进一步可以调用的RFC函数授权&#xff…

大数据-201 数据挖掘 机器学习理论 - 决策树 局部最优 剪枝 分裂 二叉分裂

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

计算机网络-总线型以太网(ethernet)-知识点小结

广域网与局域网区分: 广域网: 广域网不使用局域网技术, 传输介质 主要是光纤和电话线 常见广域网技术 综合业务数字网&#xff08;ISDN&#xff09;、 帧中继&#xff08;Frame Relay&#xff09;、 异步传输模式 局域网: 以太网--ethernet 简介: 是一种总线型局域网技术&#…

透明加密技术是什么?透明加密技术的原理与应用实践(内含代表性软件分享)

触目惊心&#xff01;10大典型间谍案例回顾 张某离职前搜集大量文件资料&#xff0c;甚至拆开电脑主机拷贝文件 私自存有5200份文件资料 其中标注绝密级的59份 机密级848份 秘密级541份 在当今这个信息化高速发展的时代&#xff0c;透明加密技术已不容忽视。那么&#xff…