1.在View的加载和绘制流程这篇文章中:传送门,有一个编舞者类,mChoreographer。
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
向MessageQueue中插入一条同步屏障消息,msg.target==null的消息,返回值mTraversalBarrier是一个int 的token值。
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//向消息队列插入一个同步屏障的消息。msg.target==null的消息
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
mChoreographer.postCallback()方法会执行mTraversalRunnable中的代码。
mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
这个会根据上面产生的token值移出MessageQueue中的同步屏障消息。
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
//移除同步屏障消息
mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
//在这个方法中会调用 measure layout draw,view的绘制绘制流程的方法
performTraversals();
}
}
还是看这行代码mHandler.getLooper().postSyncBarrier(),系统是怎么处理的。
获取了一个没有设置handler的Message。
int enqueueSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
// 这个msg.target没有被赋值
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
正常我们通过handler发送消息,handler是不允许为空的。
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
...........
}
那系统为啥要发送一个handler为空的消息呢?
先看mChoreographer发了同步屏障消息后,又做了什么?
又发送了一个异步消息:msg.setAsynchronous(true),这个消息的handler不为null。
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
//将消息设置为异步消息
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
接下来看看MessageQueue是怎么去消息的,是如何对这个同步屏障消息怎么处理的。
Message next() {
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//如果msg.target==null说明我们已经向消息队里中插入了一条屏障消息。
//此时会进入到这个循环中,找到msg.isAsynchronous==true的异步消息。
//通常我们发送的都是同步消息isAsynchronous = false的,并且msg.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());//msg.isAsynchronous==true时结束循环,说明找到了这个异步消息。
}
if (msg != null) {//找到了同步屏障的异步消息后,直接返回
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
}
} else {//没有找到的话则进入休眠直到下一次被唤醒
// No more messages.
nextPollTimeoutMillis = -1;
}
}
}
在取消的时候,先判断进行msg.target为null的判断,然后经过while循环,找到msg.isAsynchronous() == true的消息。也就是上面发送的异步消息。通常我们发送的消息都是同步消息,不会对对 msg.setAsynchronous(true);进行设置。
系统这样做的目的就是为了优先去处理这个异步消息。会把所有的同步消息放在后面,向一道屏障一样,所以这样的操作,被称为同步屏障,是同步屏障消息的处理有更高的优先级。
因为编舞者类mChoreographer 负责屏幕的渲染,需要及时的处理从底层过来的信号,以保障界面刷新的频率。
那么mChoreographer是如何处理信号的,如何进行渲染的逻辑是怎么样的,有机会再写文章进行分享。