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 dont 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是如何处理信号的,如何进行渲染的逻辑是怎么样的,有机会再写文章进行分享。