赞
踩
Android 消息机制主要指的是 Handler 的运行机制及其所依赖的 MessageQueue 和 Looper 的工作过程,Handler、MessageQueue、Looper组成一个相互联系的整体。本文先从 MessageQueue 的源码来说明其实现原理。
MessageQueue ,顾名思义,意为消息队列,其操作主要有插入和读取。插入对应的方法为 enqueueMessage()
,即往消息队列中插入一条消息,而读取对应next()
,该方法会从消息队列中取出一条消息并将其从消息队列中删除。虽然 MessageQueue 的名字包含队列(Queue),但是其底层实现采用的是单链表,这是因为链表在插入和删除方面的性能好。下面看其源码实现。
boolean enqueueMessage(Message msg, long when) { ... ...//省略 synchronized (this) { if (mQuitting) {//如果中止了,直接返回 IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); msg.recycle(); return false; } msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; 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; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
enqueueMessage()中,Message 对象 p 代表下一个消息,对于新进来的消息,如果满足条件: p == null || when == 0 || when < p.when
,那么就将它插在消息列表的最前面;否则,就按照消息触发的时间( when 字段)来插入消息。也就是说,消息的插入是按照时间顺序从小到大进行的。
接下来在看看获取消息的 next()
方法:
Message next() .....//省略 int pendingIdleHandlerCount = -1; // -1 only during first iteration // 1.如果nextPollTimeoutMillis=-1,一直阻塞不会超时。 // 2.如果nextPollTimeoutMillis=0,不会阻塞,立即返回。 // 3.如果nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis毫秒(超时) // 如果期间有程序唤醒会立即返回。 int nextPollTimeoutMillis = 0; //死循环,但是拿到消息就return了 for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } // 重要:调用到底层native的 MessageQueue // nextPollTimeoutMillis为-1,说明没有消息需要处理,在 native 中阻塞, nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; //如果target==null,那么它就是屏障,需要循环遍历,一直往后找到第一个异步的消息 if (msg != null && msg.target == null) { // Stalled by a barrier. Find the next asynchronous message in the queue. do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { //如果有消息需要处理,先判断时间有没有到,如果没到的话设置一下阻塞时间, //场景如常用的postDelay if (now < msg.when) { //计算出离执行时间还有多久赋值给nextPollTimeoutMillis, //表示nativePollOnce方法要等待nextPollTimeoutMillis时长后返回,nextPollTimeoutMillis 不为 -1 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { // 获取到消息 mBlocked = false; //链表操作,获取msg并且删除该节点 if (prevMsg != null) prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; msg.markInUse(); //返回拿到的消息 return msg; } } else { //没有消息,nextPollTimeoutMillis复位 nextPollTimeoutMillis = -1; } .....//省略 }
先说一下,MessageQueue 的数据结构为一个单向链表,Message 对象有个 next 字段保存列表中的下一个,MessageQueue 中的 mMessages 保存链表的第一个元素。
可以看到,next()
是一个无限循环的方法,读取消息时如果有消息就将该消息从消息列表中移除并返回该消息,否则就一直阻塞。
参考:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。