android 消息队列MessageQueue源码阅读
消息队列MessageQueue源码截图:
注释看出,消息队列中的消息,会由Looper进行分发处理。之前看到Looper启动消息循环调用了MessageQueue的next方法获取消息。看下这个next方法如何从消息队列中取出消息。
mPtr为native层的指针变量,为0表示消息循环已退出。
有个变量nextPollTimeoutMillis用于阻塞超时控制。nativePollOnce方法阻塞当前线程,第2个参数为线程阻塞的时间,这个时间计时结束有消息需要处理。
场景1,当前时间还没到消息执行时间,比如下面判断now < msg.when, 计算了需要等待多长时间再处理该消息,下一次for循环会调用nativePollOnce方法设置线程阻塞时间。
场景2,当前时间已经到了消息执行时间。
可以看出直接返回该message,并将消息队列的链表头节点更新为该消息节点的下一个节点(即移除该消息节点)。
场景3,消息队列里没有消息,nextPollTimeoutMillis变量置为-1,下次for循环会立即设置线程永久阻塞,无限等待。(除非有新消息插入到消息队列,调用nativeWake方法唤醒该线程,后续详细研究该流程)
这就是从消息队列中获取消息的流程,总结就是如果消息队列为空,则阻塞当前线程并等待有消息加入消息队列;若从消息队列获取到消息且消息未到处理时间,则设置阻塞当前线程,设置延迟唤醒线程处理消息;若从消息队列获取到消息且该消息已到执行时间,则取出该消息,并更新链表头节点。
以上就是从消息队列中获取消息的流程。
另外,还有一个方法enqueueMessage也很重要,作用是将消息插入消息队列。代码截图如下:
代码分析,msg = when这句代码标识该消息应该在什么时候处理。然后要做的就是将该消息加入到消息队列(准确的说是消息链表,Message是链表数据结构,其中有next引用指向下一个消息)中。
根据消息处理时间(when字段)判断:
场景1,当消息队列中没有消息时,或当前消息需要立即处理时,或当前消息的处理时刻比消息队列中第一个消息的处理时刻还要早, 此时将该消息插入到消息队列的最前面。
场景2,即该消息处理时间大于消息队列的第1个消息的处理时间,根据消息处理时间的先后排序,将该消息插入到消息队列中。
再然后就是判断如果需要唤醒消息队列线程,则调用nativeWake方法唤醒之:
Ok. 以上就是Message工作流程。
除此之外,性能优化可能会用到addIdleHandler方法,该方法如下:
看下IdleHandler介绍:
意思是一个回调接口,当一个线程即将阻塞等待更多消息,调用该回调接口。即,当消息队列中为空,或第1个消息还没到处理的时间,此时没有消息要处理,是空闲状态,则调用该回调接口。如下截图。IdleHandler常用于性能优化,利用该线程此刻没有要处理的消息,空闲不忙的时候做点事。