看了前面Looper章节之后,也许还是云里雾里的,但至少了解到Looper中每个Looper干了什么事,其中我们MessageLooper留下了两个问题。主要问题是Looper如何从MessageQueue中去取消息的。

那么我们先从MessageQueue如何压入消息开始:

MessageQueue是Message的一个收纳处,App通过Handler将Message压入到MessageQueue。

1. MessageQueue成员

    /** mimics 'this' synchronization lock */android::Mutex mLock;  //同步锁android::sp<Message> mMessages; //消息链表头;android::sp< GArrayList< IdleHandler > > mIdleHandlers; 空闲处理Handlersandroid::sp< Blob< android::sp<IdleHandler> > > mPendingIdleHandlers;bool mQuiting;    //是否暂停了bool mQuitAllowed;//是否允许暂停bool mBlocked;    //是否堵塞了// The next barrier token.// Barriers are indicated by messages with a null target whose arg1 field carries the token.int mNextBarrierToken;//Barrier的令牌public:android::sp<NativeMessageQueue> mNativeQueue;  //NativeQueue, 位于Jni层。

2. 接口

/*** Add a new {@link IdleHandler} to this message queue.  This may be* removed automatically for you by returning false from* {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is* invoked, or explicitly removing it with {@link #removeIdleHandler}.** <p>This method is safe to call from any thread.** @param handler The IdleHandler to be added.*/void addIdleHandler(const android::sp<IdleHandler>& handler);/*** Remove an {@link IdleHandler} from the queue that was previously added* with {@link #addIdleHandler}.  If the given object is not currently* in the idle list, nothing is done.** @param handler The IdleHandler to be removed.*/void removeIdleHandler(const android::sp<IdleHandler>& handler);/*** ctor*/MessageQueue(bool quitAllowed);virtual ~MessageQueue();android::sp<Message> next();void quit();int enqueueSyncBarrier(long long when);void removeSyncBarrier(int token);bool enqueueMessage(const android::sp<Message>& msg, int64_t when);bool hasMessages(const android::sp<Handler>& h);bool hasMessages(const android::sp<Handler>& h, int what, const android::sp<Object>& object);bool hasMessages(const android::sp<Handler>& h, const android::sp<Runnable>& r, const android::sp<Object>& object);void removeMessages(const android::sp<Handler>& h, int what, const android::sp<Object>& object);void removeMessages(const android::sp<Handler>& h, const android::sp<Runnable>& r, const android::sp<Object>& object);void removeCallbacksAndMessages(const android::sp<Handler>& h, const android::sp<Object>& object);

2.1. 先介绍一下IdleHandler。

IdlerHandler是定义在MessageQueue的一个内部类:

 /*** Callback interface for discovering when a thread is going to block* waiting for more messages.*/class IdleHandler:virtual public Object {DECLARE_DYNAMIC(IdleHandler);public:IdleHandler();/*** Called when the message queue has run out of messages and will now* wait for more.  Return true to keep your idle handler active, false* to have it removed.  This may be called if there are still messages* pending in the queue, but they are all scheduled to be dispatched* after the current time.*/virtual bool queueIdle()=0;};

根据上下文意思和注释分析来看,IdleHandler是为了提高效率,当Looper在进入空闲等待状态前,如果应用程序注册了IdleHandler接口来处理一些事情,那么就会先执行这里IdleHandler,然后再进入等待状态。

IdleHandler只有一个成员函数queueIdle,执行这个函数时,如果返回值为false,那么就会从应用程序中移除这个IdleHandler,否则的话就会在应用程序中继续维护着这个IdleHandler,下次空闲时仍会再执会这个IdleHandler。MessageQueue提供了addIdleHandler和removeIdleHandler两注册和删除IdleHandler。

2.2. 构造函数

MessageQueue::MessageQueue(bool quitAllowed):mPendingIdleHandlers(NULL),mQuiting (false),mQuitAllowed(quitAllowed),mBlocked(false) {mIdleHandlers = new GArrayList<IdleHandler>();//创建IdleHandler数组链表sp<NativeMessageQueue> nativeMessageQueue = new NativeMessageQueue();//创建NativeMessageQueuemNativeQueue = nativeMessageQueue;
}

2.3. 插入队列

bool MessageQueue::enqueueMessage(const sp<Message>& msg, int64_t when) {GLOGENTRY();if (msg->isInUse()) { //msg是否正在使用中return false;}if (msg->target == NULL) { //没有Target return false;}bool needWake;{AutoMutex _l(mLock);  //同步锁if (mQuiting) {       //正在暂停中,那么不插入return false;}msg->when = when;sp<Message> p = mMessages;  //消息队列头if (p == NULL || when == 0 || when < p->when) { /**把Msg插在头部的情况:*--p是空的;*--message的When==0,也就是立即需要处理的,*--when < p->when,也就是when的时间最早*/// New head, wake up the event queue if blocked.msg->next = p;mMessages = msg;needWake = mBlocked;  // new head, might need to wake up 是否需要wake要看目前是否已经堵塞住了。} else {/*这种情况是将msg插入在队列之中的,通常不需要执行wake动作;**/// Inserted within the middle of the queue.  Usually we don't have to wake// up the event queue unless there is a barrier at the head of the queue// and the message is the earliest asynchronous message in the queue.needWake = mBlocked && p->target == NULL && msg->isAsynchronous();//p->target == Null表示MessageQueue头部存在一个barrier栏栅//也就是若p头部存在barrier且已经堵塞,而且msg是一个异步消息,这样才需要唤醒?为什么?sp<Message> prev;for (;;) {prev = p;p = p->next;if (p == NULL || when < p->when) {  //找到第一个p->when大于msg->when的结点break;}if (needWake && p->isAsynchronous()) { //若needWake为True,而且p中存在一个异步的消息,那么将needWake设置为false,这又是为什么needWake = false;}}msg->next = p;  // invariant: p == prev.nextprev->next = msg; //插入消息}}if (needWake) { //若需要wake,那么执行NativeQueue的Wake动作,最后执行到了事件Looper的Wake中;if (mNativeQueue != NULL) {mNativeQueue->wake();}}return true;
}

2.4. 取出消息

sp<Message> MessageQueue::next() {int pendingIdleHandlerCount = -1;  // -1 only during first iterationint nextPollTimeoutMillis = 0;     //初次进来,将PollTimeOUt设置为0while (true) {if (nextPollTimeoutMillis != 0) {  IPCThreadState::self()->flushCommands();//这个没怎么看懂,应该是跟驱动交流下,刷新下信息}if (mNativeQueue != NULL) {mNativeQueue->pollOnce(nextPollTimeoutMillis); /**进入了事件Looper的 pollOnce,初次进来时,nextPollTimeoutMillis为0,Pollonce的poll_wait会立即返回,*如果后续的while循环中,发现有延时msg,那么nextPollTimeoutMillis > 0, pollonce也将通过epoll_wait消耗那部分的时间,然后返回;*/}// synchronized (this){AutoMutex _l(mLock); //同步锁if (mQuiting) { //如果已经暂停了,那么直接返回, Message Looper收到NULL信息之后,将会break出for循环。return NULL;}// Try to retrieve the next message.  Return if found.long long now = uptimeMillis(); //取出现在的时间sp<Message> prevMsg = NULL;const sp<Message> msg = mMessages; //取出队列// Stalled by a barrier.  Find the next asynchronous message in the queue./**若msg->target == NULL, 说明存在barrier,barrier的目的是,后面的同步消息将堵塞,异步消息可以拿出来执行,所以需要找出异步消息*/if (msg != NULL && msg->target == NULL) {do {prevMsg = msg;msg = msg->next;} while (msg != NULL && !msg->isAsynchronous());//寻找异步消息}if (msg != NULL) {/*若msg !=NULL ,不管是异步的还是同步的 long long when = msg->when; if (now < msg->when) {*判定时间,看Message是否准备好了,若没有准备好,计算出下一次Message到时的时间;*到下一个触发时间的时候,我们再轮询到这里来,而中间的时间将通过pollOnce消耗掉 */long long when = msg->when;if (now < msg->when) {// Next message is not ready.  Set a timeout to wake up when it is ready.nextPollTimeoutMillis = (int) min(msg->when - now, INT_MAX);//计算下一次Message到时消息的时间} else {// Got a message.mBlocked = false;if (prevMsg != NULL) {prevMsg->next = msg->next;} else {mMessages = msg->next;}msg->next = NULL;if (false)GLOGV("MessageQueue Returning message: %s",msg->toString()->string());msg->markInUse();return msg;}}else {/**否则表示Messages中没有任何消息,设置nextPollTimeouMillis = -1,*表示pollOnce将需要无穷的等待,直到有事件唤醒*/// No more messages.nextPollTimeoutMillis = -1;}// If first time idle, then get the number of idlers to run.// Idle handles only run if the queue is empty or if the first message// in the queue (possibly a barrier) is due to be handled in the future.if (pendingIdleHandlerCount < 0&& (mMessages == NULL || now < mMessages->when)) {pendingIdleHandlerCount = mIdleHandlers->size();}if (pendingIdleHandlerCount <= 0) {// No idle handlers to run.  Loop and wait some more.mBlocked = true;continue;}if (mPendingIdleHandlers == NULL) {mPendingIdleHandlers = new Blob<sp<IdleHandler> >(max(pendingIdleHandlerCount, 4));}mPendingIdleHandlers = mIdleHandlers->toArray(mPendingIdleHandlers);}//既然需要等待了,那么执行注册了的那写IdleHandlers;// Run the idle handlers.// We only ever reach this code block during the first iteration.for (int i = 0; i < pendingIdleHandlerCount; i++) {const sp<IdleHandler> idler = (*mPendingIdleHandlers)[i];(*mPendingIdleHandlers)[i] = NULL;  // release the reference to the handlerbool keep = false;// try {keep = idler->queueIdle();// } catch (Throwable t) {//    Log.wtf("MessageQueue", "IdleHandler threw exception", t);// }if (!keep) { //根据QueueIdle的返回值,删除或者保留该idler// synchronized (this){AutoMutex _l(mLock);mIdleHandlers->remove(idler);}}}/**执行完这些IdleHandler之后,线程下次调用nativePollOnce函数时,*就不设置超时时间了,因为,很有可能在执行IdleHandler的时候,*已经有新的消息加入到消息队列中去了,因此,要重置nextPollTimeoutMillis的值*/// Reset the idle handler count to 0 so we do not run them again.pendingIdleHandlerCount = 0;// While calling an idle handler, a new message could have been delivered// so go back and look again for a pending message without waiting.nextPollTimeoutMillis = 0;}//继续轮询;}

先说说Block

Block更改状态的情况:

1). 没有取到消息,即Message要么还没到时,要么为NULL,;且这时候,没有IdleHandler要处理,那么mBlocked设置为true;

2). 当我们取到了满足要求的消息,并准备返回之前,将mBlocked设置为false;

mBlocked将影响插入msg到MessageQueue时是否需要Wake动作
需要根据mBlocked来判定条件的条件的情况:

1). 当插入消息时,若发现msg需要插入到头部,那么wakeup将根据mBlocked来设置值,若mBlock为true这需要wake.

2). 若不是插入到头部,且MessageQueue目前是barrier状态,那么除非msg是第一个异步的消息,wake将设置为true;

    if (p == NULL || when == 0 || when < p->when) {// New head, wake up the event queue if blocked.msg->next = p;mMessages = msg;needWake = mBlocked;  // new head, might need to wake up} else {// Inserted within the middle of the queue.  Usually we don't have to wake// up the event queue unless there is a barrier at the head of the queue// and the message is the earliest asynchronous message in the queue.needWake = mBlocked && p->target == NULL && msg->isAsynchronous();//若msg是异步,且p是barrier,且mBlock状态sp<Message> prev;for (;;) {prev = p;p = p->next;if (p == NULL || when < p->when) {break;}if (needWake && p->isAsynchronous()) { //若还存在其他异步的,表示Msg不是第一个异步的,那么也不需要wakeneedWake = false;}}msg->next = p;  // invariant: p == prev.nextprev->next = msg;}

这就是Looper中取出消息的一个过程分析;

总结一下:

a). MessageQueue在创建时,会创建一个NativeQueue

程序的主线程在进入消息循环过程前,会在Native中创建一个事件Looper, 该Looper中创建一Pipe,管道的作用是使得程序主线程在消息队列为空时可以进入空闲等待状态,并且使得当应用程序的消息队列有消息需要处理时唤醒应用程序的主线程。

b). 当Message Looper进入到MessageQueue::Next取消息时,先让NativeQueue进入到Pollonce,消耗掉nextPollTimeoutMillis的时间值:这个nextPollTimeoutMillis在后续循环中会根据Queue中Message的情况来设置不同的值;

c). MessageQueue尝试去取下一个消息,

若第一个消息是延时消息且未到时,那么更新nextPollTimeoutMillis,

若是Barrier消息,表示存在一个栏栅,栏栅后面的同步消息是不同执行的,那么取后面的异步消息;

若第一个消息不是barrier,且也到时了,那么去出来,将堵塞状态更新为false;

若第一个消息为NULL, 表示没有消息,那么更新nextPollTimeoutMillis = -1;

d). 若没有取到消息,那么进入到IdleHandler,

若IdlerHandler也不存在,那么将mBlock设置为true;

若存在IdlerHandler,那么执行IdleHandler,等IdleHandler执行结束了,则可能这短时间Message满足要求了,那么将nextPollTimeoutMillis重置为0;

然后继续While循环;

2.5. enqueueSyncBarrier

enqueueSyncBarrier并不需要Wake动作

int MessageQueue::enqueueSyncBarrier(long long when) {// Enqueue a new sync barrier token.// We don't need to wake the queue because the purpose of a barrier is to stall it.//synchronized (this) {AutoMutex _l(mLock);const int token = mNextBarrierToken++;     //生成令牌const sp<Message> msg = Message::obtain(); //生成barrier消息msg->arg1 = token;                         //args记录token信息sp<Message> prev = NULL;sp<Message> p = mMessages;if (when != 0) {while (p != NULL && p->when <= when) {   //根据When信息找到插入的位置prev = p;p = p->next;}}if (prev != NULL) {  // invariant: p == prev.nextmsg->next = p;prev->next = msg;} else {msg->next = p;mMessages = msg;}return token;
}

2.6. removeSyncBarrier

void MessageQueue::removeSyncBarrier(int token) {// Remove a sync barrier token from the queue.// If the queue is no longer stalled by a barrier then wake it.bool needWake;AutoMutex _l(mLock);sp<Message> prev = NULL;sp<Message> p = mMessages;while (p != NULL && (p->target != NULL || p->arg1 != token)) { //根据target和token找到barrier的msgprev = p;p = p->next;}if (prev != NULL) {  prev->next = p->next;needWake = false;  //若barrier在queue的中间则不需要wake} else {  //barrier在Queueu的头部,那么需要唤醒mMessages = p->next;needWake = mMessages == NULL || mMessages->target != NULL;}p->recycle(); //将barrier回收if (needWake) {if (mNativeQueue != NULL) {mNativeQueue->wake(); //唤醒}}
}

2.7. Quit

void MessageQueue::quit() {if (!mQuitAllowed) {GLOGE("Main thread not allowed to quit.");}//synchronized (this) {AutoMutex _l(mLock);if (mQuiting) {return;}mQuiting = true;if (mNativeQueue != NULL) { //Quit之后需要进行WakemNativeQueue->wake();}
}

Android 线程4件套 MessageQueue Message Looper Handler之MessageQueue相关推荐

  1. MessageQueue Message Looper Handler的解释说明

    总结4个关键概念  1.MessageQueue:是一种数据结构,见名知义,就是一个消息队列,存放消息的地方.每一个线程最多只可以拥有一个MessageQueue数据结构.  创建一个线程的时候,并不 ...

  2. Android 线程4件套 MessageQueue Message Looper Handler之Looper

    Android驱动线程消息公四件套: 消息载体:Message 消息队列:MessageQueue 消息循环:Looper 消息处理:Handler 以Looper为基础,形象的表示为一个无限循环的环 ...

  3. Android线程之异步消息处理机制(二)——Message、Handler、MessageQueue和Looper

    异步消息处理机制解析 Android中的异步消息处理主要有四个部分组成,Message.Handler.MessageQueue和Looper. 1.Message Message是在线程之间传递的消 ...

  4. 深入理解异步消息处理机制Message,handler,MessageQueue,looper

    本文转自: http://www.cyqdata.com/android/article-detail-36658 本篇深入理解Android消息队列原理篇,将为您讲述Android世界中的消息机制, ...

  5. Android 中Message,MessageQueue,Looper,Handler详解+实例

    一.几个关键概念 1.MessageQueue:是一种数据结构,见名知义,就是一个消息队列,存放消息的地方.每一个线程最多只可以拥有一个MessageQueue数据结构. 创建一个线程的时候,并不会自 ...

  6. Message,MessageQueue,Looper,Handler详解+实例

    Message,MessageQueue,Looper,Handler详解+实例 原文地址 Android的Handler使用(这篇简单介绍Handler的使用) 一.几个关键概念 1.Message ...

  7. Android线程管理(一)

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

  8. Android线程间通信机制

    Android线程间通信机制 当android应用程序运行时,一个主线程被创建(也称作UI线程),此线程主要负责处理UI相关的事件,由于Android采用UI单线程模型,所以只能在主线程中对UI元素进 ...

  9. Android 消息处理机制(Looper、Handler、MessageQueue,Message)

    原文:[简书原文](http://www.jianshu.com/p/02962454adf7)> 另外本人自己开了开了个人博客 fanmingyi.cn 不定时更新[跳转到个人博客](http ...

最新文章

  1. Java项目:酒店管理系统(java+SSM+jsp+mysql+maven)
  2. 云栖大会的最后,阿里巴巴数据安全放了个大招!
  3. 鹅厂2020暑期实习第二次一面
  4. 【OpenGL】八、初始化 OpenGL 渲染环境 ( 导入 OpenGL 头文件 | 链接 OpenGL 库 | 将窗口设置为 OpenGL 窗口 | 设置像素格式描述符 | 渲染绘制 ) ★
  5. cnpm install -g live-server 安装服务
  6. adf开发_ADF BC:创建绑定到业务组件的UI表
  7. Ant Design Pro 2.0/umijs站点配置到非站点根目录下处理
  8. linux 多块硬盘 snmp,[技术干货] Zabbix使用snmp监控Linux硬盘大小不准问题
  9. java oracle 视图不存在_java – 获取异常ORA-00942:表或视图不存在 – 插入现有表时...
  10. WordPress Shortcode(简码)介绍及使用详解
  11. No boot device avalible,Press any key to reboot the system
  12. SpringBoot +spring security 与CSRF有关的几个 问题
  13. MSP430开发笔记之五:硬件IO中断与IR红外接收
  14. python程序写诗_python:为你写诗
  15. qt 获取用户缩放,Qt-如何创建随窗口缩放并保持纵横比的图像?
  16. 计算机c盘内存怎么转给d盘,C盘空间太大怎么把空间转到D盘或E盘
  17. C语言飞机大战小游戏(2万字!完整精讲解版+源代码)
  18. /proc/cpuinfo参数说明查看CPU参数
  19. 深度学习--解决模型过拟合的问题
  20. 【转】使用 HTML5 设计辅助功能

热门文章

  1. bootstrap实现导航栏的响应式布局,当在小屏幕、手机屏幕浏览时自动折叠隐藏
  2. ..\OBJ\PRESSURE_SYSTEM.axf: Error: L6218E: Undefined symbol FLASH_ErasePage (referred from flash.o).
  3. 【Python学习笔记】3. Python3 基础语法
  4. PHP执行shell_exec方法失败
  5. HTML+JS+websocket 实现联机“游戏王”对战(十三)- 实机演示视频
  6. ios小米手环6最新固件获取auth_key更换第三方表盘
  7. 【工业视觉】Halcon常用教程
  8. 记一次hydra密码破解神器的学习
  9. android应用加固后闪退,梆梆加固,启动就闪退了
  10. 如何卸载“卸载驱动”图标为灰色图标