更多博客 https://70kg.info
保存在MessageQueue
的Message mMessages
成员变量中,通过message
中的next
维护一个单向链表。message
本身一直在java层,和native
的message没有直接操作关系。looper
分发的消息都是通过messagequeue.mMessages
间接获取的。当sendMessage
时,进入messagequeue
的enqueueMessage
方法,
Message p = mMessages;
boolean needWake;
//代表MessageQueue没有消息,或者msg的触发时间是队列中最早的
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
//mBlocked在空消息为true
needWake = mBlocked;
} 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();
Message prev;
//遍历mMessages 找到合适位置插入msg
for (;;) {
prev = p;
p = p.next;
//当p==null 说明是链表的最后一个的next 要将msg插入到链表的最后,当when < p.when说明后面还有时间没到的在排队,插入到这些的前面
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
接受消息在messagequeue.next()
中,nativePollOnce(ptr, nextPollTimeoutMillis);
方法是陷入到native
层,一般nextPollTimeoutMillis
都为0,说明要马上处理message
,就会执行下面的语句。当没有消息时,nextPollTimeoutMillis
为-1,表示无限阻塞,直到mEpollFd所监控的文件描述符发生了要监控的IO事件后或者监控时间超时后,线程就从epoll_wait返回了,也就会执行下面的操作,说明有新的message可以处理了。也就是说没消息的阻塞是在nativePollOnce
实现的(具体是在native looper ::pollInner),但是这个阻塞不是忙等待,而是闲等待,让出CPU时间。
A. Android应用程序的消息处理机制由消息循环、消息发送和消息处理三个部分组成的。
B. Android应用程序的主线程在进入消息循环过程前,会在内部创建一个Linux管道(Pipe),这个管道的作用是使得Android应用程序主线程在消息队列为空时可以进入空闲等待状态,并且使得当应用程序的消息队列有消息需要处理时唤醒应用程序的主线程。
C. Android应用程序的主线程进入空闲等待状态的方式实际上就是在管道的读端等待管道中有新的内容可读,具体来说就是是通过Linux系统的Epoll机制中的epoll_wait函数进行的。
D. 当往Android应用程序的消息队列中加入新的消息时,会同时往管道中的写端写入内容,通过这种方式就可以唤醒正在等待消息到来的应用程序主线程。
E. 当应用程序主线程在进入空闲等待前,会认为当前线程处理空闲状态,于是就会调用那些已经注册了的IdleHandler接口,使得应用程序有机会在空闲的时候处理一些事情。
—->Android应用程序消息处理机制(Looper、Handler)分析