好了,确实这个字段就表示是否阻塞的意思,再去看看enqueueMessage
方法中,唤醒机制:
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
boolean needWake;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
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;
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
- 当链表为空或者时间小于表头消息时间,那么就插入表头,并且设置是否唤醒为
mBlocked
。
再结合上述的例子,也就是当有新消息要插入表头了,这时候如果之前是阻塞状态(mBlocked=true),那么就要唤醒线程了。
- 否则,就需要取链表中找到某个节点并插入消息,在这之前需要赋值
needWake = mBlocked && p.target == null && msg.isAsynchronous()
也就是在插入消息之前,需要判断是否阻塞,并且表头是不是屏障消息,并且当前消息是不是异步消息。 也就是如果现在是同步屏障模式下,那么要插入的消息又刚好是异步消息,那就不用管插入消息问题了,直接唤醒线程,因为异步消息需要先执行。
- 最后一点,是在循环里,如果发现之前就存在异步消息,那就还是设置是否唤醒为
false
。
意思就是,如果之前有异步消息了,那肯定之前就唤醒过了,这时候就不需要再次唤醒了。
最后根据needWake
的值,决定是否调用nativeWake
方法唤醒next()
方法。
[](()8、同步屏障和异步消息是怎么实现的?
其实在Handler
机制中,有三种消息类型:
-
同步消息
。也就是普通的消息。 -
异步消息
。通过setAsynchronous(true)设置的消息。 -
同步屏障消息
。通过postSyncBarrier方法添加的消息,特点是target为空,也就是没有对应的handler。
这三者之间的关系如何呢?
-
正常情况下,同步消息和异步消息都是正常被处理,也就是根据时间when来取消息,处理消息。
-
当遇到同步屏障消息的时候,就开始从消息队列里面去找异步消息,找到了再根据时间决定阻塞还是返回消息。
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
也就是说同步屏障消息不会被返回,他只是一个标志,一个工具,遇到它就代表要去先行处理异步消息了。
所以同步屏障和异步消息的存在的意义就在于有些消息需要“加急处理”
。
[](()9、同步屏障和异步消息有具体的使用场景吗?
使用场景就很多了,比如绘制方法scheduleTraversals
。
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 同步屏障,阻塞所有的同步消息
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 通过 Choreographer 发送绘制任务
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
在该方法中加入了同步屏障,后续加入一个异步消息MSG_DO_SCHEDULE_CALLBACK
,最后会执行到FrameDisplayEventReceiver
,用于申请VSYNC信号。
[](()10、Message消息被分发之后会怎么处理?消息怎么复用的?
再看看loop方法,在消息被分发之后,也就是执行了dispatchMessage
方法之后,还偷偷做了一个操作——recycleU