. 消息的入列过程首先在Handler中调用enqueueMessage(Message msg, long when)方法。该方法的主要目的是将消息添加到MessageQueue中并对其进行排序。当消息到达时,Handler会根据消息的执行时间来确定其在队列中的位置。如果消息是队列中的第一个消息,或者它的执行时间比队列中的其他消息早,那么它会被放在队列的前面;否则,它会被放在合适的位置以保持队列按执行时间排序。
2. 当需要从MessageQueue中取出消息时,主要逻辑在Handler的loop()方法中。这个方法是一个死循环,会一直执行直到Looper被销毁。在循环中,Handler会检查是否有新的消息需要处理。如果有新的消息,那么就会从队列中取出并处理这些消息。这就是消息的出列过程。
以下是重构后的代码:
```java
boolean enqueueMessage(Message msg, long when) { //对消息的重新排序,通过判断消息队列里是否有消息以及消息的时间对比 msg.when = when; Message p = mMessages; //把刚进入消息队列的消息置位消息队列的第一条消息 if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; needWake = mBlocked; } else { //根据时间排序,为刚进入队列的消息寻找合适的位置 Message prev; for (;;) { prev = p; p = p.next; } msg.next = p; // invariant: p == prev.next prev.next = msg; } }
```
总的来说,消息的入列就是根据Message的when属性的大小进行排序,先执行的放在队列的前面。当需要从MessageQueue中取出消息时,主要逻辑在Handler的loop()方法中,这是一个死循环,会一直执行直到Looper被销毁。在循环中,Handler会检查是否有新的消息需要处理。如果有新的消息,那么就会从队列中取出并处理这些消息。这就是消息的出列过程。
下面我们来分析一下Linux中的进程间通信机制:管道(pipe)。
原理:在Linux中,内存中有一个特殊的文件,这个文件有两个句柄(引用),一个是读取句柄,一个是写入句柄。主线程的Looper从消息队列中读取消息,当读完所有消息时,进入睡眠状态,主线程被阻塞。子线程往消息队列发送消息,并往管道文件写数据,此时主线程被唤醒。唤醒后的主线程只是为了读取消息,当消息读取完毕,再次进入睡眠状态。
我们来看一下如何取出消息队列中的消息。关键代码如下:
```java
for (;;) { //取出消息队列的消息,可能会阻塞
Message msg = queue.next(); // might block
}
```
其中,`queue.next()`方法用于获取消息队列中的下一个消息。如果当前没有消息,此方法可能会被阻塞。
接下来我们看一下消息是如何取出来的。我们看取出消息的逻辑,关键代码如下:
```java
Message next() {
for (;;) {
Message prevMsg = null;
Message msg = mMessages;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
return msg;
}
}
```
示范一个简单的出列流程,关键代码如下:
```java
Message dequeue() {
Message nextMsg = null;
for (;;) {
Message head = mMessages;
if (head == null) break;
nextMsg = head.next;
head.next = null;
if (mMessages == head) mMessages = null;
}
return nextMsg;
}
```
现在我们已经知道了消息的入列和出列过程。