在之前的文章中,looper.loop方法中,取消时候的时候调用了messagequeue.next()。
其中我们可以看到,msg不为null,并且msg.target为null。这种情况,handler不就是为null了。那么还怎么处理消息。 往下看,红框里有一个判断,它取出了一条消息。第二个判断条件是message的方法。看一下。
注释是,如果是异步消息就会返回true,那么同步消息就会返回false。所以上面的代码的意思就是一直找消息,知道找到一条异步消息就跳出循环。
既然我们已经知道这一步的操作是为了取出一个异步消息,那么收钱从头来看,target为什么为null,走入了这个判断。
1.首先message中与asyn相关的就两个,(获取同步异步和设置同步异步,与target不相关)
2.在看handler,handler方法最后都会把自己作为this传入
3.那么接下来就要从messagequeue来查看了。可以看到这个方法
同步屏障(所谓的)
我把注释也贴了上去。看注释就懂了。向消息队列中发布一个同步屏障,当遇到障碍的时候,列队中的同步消息会被阻止执行。直到找到一个异步消息。
从红框内,我们也可以看到,msg.target并没有被赋值,由此可见,会走到我们开头图片的方法中。
那我们就来说说消息的类型(同步消息、异步消息、同步屏障消息)
什么是同步屏障?
简单的来说就是一个target为null的消息,他的作用就是当代码发现这个同步屏障后,阻止同步消息的读取,去找队列中的异步消息。
什么是同步消息和异步消息?
//可以看到同步消息和异步消息的区别,仅仅就是一个flag的值的不同而已。
public void setAsynchronous(boolean async) {
if (async) {
flags |= FLAG_ASYNCHRONOUS;
} else {
flags &= ~FLAG_ASYNCHRONOUS;
}
}
同步屏障用来做什么?
流程如果所示(其实就是取异步消息):
那么我们此时就知道流程了。
但是 postSyncBarrier 这个方法我们貌似一直没有用过。可以看到方法上有一个注解。@UnsupportedAppUsage,我理解的意思就是不支持app去使用。????那是谁用的。我们源码中搜索一下。
看到了一个老朋友。
这里不提及太多,以后有屏幕刷新的文章在单独介绍。简单的说就是屏幕刷新一般为60hz~120hz,每秒刷新60到120次,对用来说体验是非常重要的,所以肯定要保证系统的刷新率优先,所以同步屏障就可以解决这个问题。当然说起屏幕刷新也涉及到vsync同步信号等,以后有时间更一篇屏幕刷新的文章。
同步屏障用在哪里?
ViewRootImpl.java(device中也用到,这里不说明了。)
调用requestLayout或者invalidate时,会在主线程消息队列中插入一个同步屏障消息,
同时注册接收Vsync的监听;当接受到Vsync通知,会发送一个异步消息,执行真正的绘制事件:
此时会移除消息队列中的同步屏障消息,然后才会执行绘制操作
@UnsupportedAppUsage
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
void unscheduleTraversals() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
mChoreographer.removeCallbacks(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
最后,我们知道同步屏障是什么,用来做什么,就可以了。有兴趣可以多看看源码,研究下。