精简版回答
同步屏障就是屏蔽同步消息的同时允许异步消息通过
详细版回答
同步屏障(SyncBarrier,翻译成同步栅栏也可以)
Message分为同步和异步
平时我们创建的Message默认都是同步类型的,有些时候需要创建异步Message 通过设置setAsynchronous(true)将Message指定为异步
同步屏障如何定义
同步屏障就是插入到Handler里MessageQueeen里的特殊Message
同步屏障如何实现
既然是个特殊的Message,那么特殊在哪? 这个Message特殊在target是空的,这样的Message就是具体担当同步屏障角色的特殊Message,也就是栅栏本体。 众所周知MessageQueeen总是在不停的遍历消息队列,当它发现targe为空的Message时,就认为发现一个同步屏障,然后继续遍历,寻找isAsynchronous的消息,也就是寻找消息类型为异步的Message,找到后执行这个消息,而普通的同步消息则得不到执行,实现屏障拦截的效果,除非将这个target为空的Message从MessageQueeen移除,普通的同步消息才能得到执行。
Handler.java 遍历时发现同步屏障
Message next() {
if (msg != null && msg.target == null) {//发现同步屏障
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());//直到找到异步消息为止
}
如何给MessageQueeen插入一个同步屏障
Handler.java 里有个私有方法,这就是给MessageQueeen插入一个同步屏障,返回值是一个同步屏障toekn,这个token用于删除一个同步屏障时使用。
private int postSyncBarrier(long when) {}//添加一个同步屏障
public void removeSyncBarrier(int token){}//删除一个同步屏障
插入一个同步屏障
Android的UI绘制时需要ViewRootImpl参与其中
ViewRootImpl.java
在调用requestLayout请求布局时会触发scheduleTraversals
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//这里这里这里!插入一个同步屏障
//mHandler是Choreographer里定义的FrameHandler的实例
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//这里注册的Callback回调,会被Vsync信号触发,也就是当硬件发起垂直同步信号后,这里的回调会被触发执行绘制动作,由于Vsync的优先级很高,所以开启同步屏障保障Vsync相关的操作优先独占的得到执行
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);//关注这个mTraversalRunnable
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
创建异步消息
Choreographer.java
看下postCallback的实现,同步屏障就是屏蔽同步消息,保障异步消息的执行,异步消息就是这里创建,并插入MessageQueeen的
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 {
///上面看到的mTraversalRunnable被传进来,成为这里的action
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);//异步消息诞生了!!!!!!!
mHandler.sendMessageAtTime(msg, dueTime);
//mHandler是Choreographer里定义的FrameHandler的实例
}
}
}
截至现在 同步屏障也有了异步Message也有了,MessageQueen的工作状态进入同步屏障模式,在next()中逐步消费这些Message
移除同步屏障
回到ViewRootImpl.java
//mTraversalRunnable就是下面这个类的实例,异步Message执行时会回调这里
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
//移除刚才添加的同步屏障后执行performTraversals()去具体的绘制UI
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);//移除同步屏障
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
总结
- 插入同步屏障
- 插入异步消息
- 消费异步消息
- 移除同步屏障
- 同步屏障是系统私有方法,对普通开发者不开放,除非反射