同步屏障
博客: Handler同步屏障机制的原理和使用场景_u013728021的博客-CSDN博客
Android中同步屏障的应用及简析 - 简书 (jianshu.com)
什么是同步屏障:
Handler的消息分为两种:同步消息和异步消息。
1 2 3 4 5 6 7 8 9 10 11 12 public boolean isAsynchronous () { return (flags & FLAG_ASYNCHRONOUS) != 0 ; } public void setAsynchronous (boolean async) { if (async) { flags |= FLAG_ASYNCHRONOUS; } else { flags &= ~FLAG_ASYNCHRONOUS; } }
这两种消息在常规使用中毫无不同之处。但是当使用同步屏障后就不同了。
设置使用同步屏障后,只会获取和分发Looper里面的异步消息,如果没有异步消息,就会进入阻塞。
当设置了同步屏障之后,next函数将会忽略所有的同步消息,返回异步消息。换句话说就是,设置了同步屏障之后,Handler只会处理异步消息。再换句话说,同步屏障为Handler消息机制增加了一种简单的优先级机制,异步消息的优先级要高于同步消息。
如何使用
通过MessageQueue的postSyncBarrier方法在链表头部插入一个target = null 的Message
发送一个异步消息
1 发送异步消息的方式:Message.setAsynchronous(true)
设置同步屏障
通过MessageQueue里的postSyncBarrier函数设置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 private int postSyncBarrier (long when) { synchronized (this ) { final int token = mNextBarrierToken++; 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 ) { msg.next = p; prev.next = msg; } else { msg.next = p; mMessages = msg; } return token; } }
方法分析:这个函数创建了一个Message对象然后插入到了消息列表头部的位置,这个消息的最大特征就是他的target为null。我们普通发的消息,在底层都设置了target的值。
1 2 3 4 5 6 private boolean enqueueMessage (MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this ; return queue.enqueueMessage(msg, uptimeMillis); }
总结:
同步屏障就是需要通过MessageQueue里的postSyncBarrier方法添加进入一个target字段为空的Message。
同步屏障的应用
View的创建: 在ViewRootImpl的requestLayout开启绘制机制的时候:
1 2 3 4 5 6 7 8 9 10 @Override public void requestLayout () { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true ; scheduleTraversals(); } }
Android框架为了更快的响应ui刷新事件在ViewRootImpl.scheduleTraversals中使用了同步屏障。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void scheduleTraversals () { if (!mTraversalScheduled) { mTraversalScheduled = true ; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null ); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } }
mTraversalRunnable 调用了 performTraversals 执行measure、layout、draw
为了让mTraversalRunnable尽快被执行,在发消息之前调用MessageQueue.postSyncBarrier设置了同步屏障。