Handler同步屏障

Posted guangdeshishe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Handler同步屏障相关的知识,希望对你有一定的参考价值。

Handler同步屏障功能小结

  • MessageQueue.postSyncBarrier发送了一个同步屏障消息后,所有的同步消息(普通Message)都不能被执行,只有被标记为异步的Message才能执行;
  • MessageQueue.removeSyncBarrier移除屏障消息后,普通消息才能正常继续执行;
  • 正常的消息Message.target指向Handler,并且Message默认是同步消息,如果想变成异步消息,可以调用Message.setAsynchronous(true)方法,或者Handler初始化的时候public Handler(boolean async)传入true,之后通过该Handler发送的消息就都是异步消息了
  • 发送同步屏障本质上只是往MessageQueue中插入一个Message.target=null的消息
  • MessageQueue.next方法中检测到有同步屏障消息时,则会开启一个while循环过滤出异步消息继续执行

源码分析

  • MessageQueue.postSyncBarrier 该API不能被APP正常调用,也没有这个必要,因为APP想要不受同步屏障的影响,可以将Message设置为异步消息即可

    @UnsupportedAppUsage
    @TestApi
    public int postSyncBarrier() 
    	return postSyncBarrier(SystemClock.uptimeMillis());
    
    
    private int postSyncBarrier(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++;
    		final Message msg = Message.obtain();//创建一个Message,但是没有设置target
    		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;
    	
    
    
  • MessageQueue.next方法中,根据msg.target == null来判断是同步屏障消息,从而开始while循环只处理异步消息

    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());
    
    
  • Handler初始化时可以指定发送的消息是同步的还是异步的

    public Handler(boolean async) 
    	this(null, async);
    
    public Handler(@Nullable Callback callback, boolean async) 
    	mAsynchronous = async;
    
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
    		long uptimeMillis) 
    	msg.target = this;
    	msg.workSourceUid = ThreadLocalWorkSource.getUid();
    
    	if (mAsynchronous) //标记为异步消息
    		msg.setAsynchronous(true);
    	
    	return queue.enqueueMessage(msg, uptimeMillis);
    
    
  • ViewRootImpl.java中应用同步屏障功能;事件分发消息不受影响,因为设置成了异步消息

    void scheduleTraversals() 
    	if (!mTraversalScheduled) 
    		mTraversalScheduled = true;
    		//执行同步前发送同步屏障消息
    		mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
    		//请求并等待垂直同步信号VSync
    		mChoreographer.postCallback(
    				Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    		notifyRendererOfFramePending();
    		pokeDrawLockIfNeeded();
    	
    
    void doTraversal() 
    	if (mTraversalScheduled) 
    		mTraversalScheduled = false;
    		//移除垂直同步屏障
    		mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
    
    		if (mProfile) 
    			Debug.startMethodTracing("ViewAncestor");
    		
    		//开始真正绘制
    		performTraversals();
    
    		if (mProfile) 
    			Debug.stopMethodTracing();
    			mProfile = false;
    		
    	
    
    public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) 
    	SomeArgs args = SomeArgs.obtain();
    	args.arg1 = event;
    	args.arg2 = receiver;
    	Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
    	msg.setAsynchronous(true);//事件分发消息不受影响,因为设置为异步消息
    	mHandler.sendMessage(msg);
    
    

应用场景

  • ViewRootImpl.java中,绘制流程开始之前,会通过主线程的MessageQueue发送一个同步消息屏障,然后开始等待垂直同步信号VSync,等待垂直同步信号这段时间内,所有在主线程Handler发送的同步消息都不能被及时执行,这样做可以保证垂直同步信号到来时可以及时的执行绘制流程,保证UI的流畅性
  • 为了保证我们主线程Handler消息能及时处理,可以调用Message.setAsynchronous(true)方法将Message设置为异步消息

以上是关于Handler同步屏障的主要内容,如果未能解决你的问题,请参考以下文章

Android-Handler同步屏障

什么是Handler的同步屏障机制?

深入源码分析Handler 消息机制 LooperMessageQueue 消息同步屏障IdleHandlerMessage 复用

(4.1.10.8)Android Handler之同步屏障机制(sync barrier)

Handler sync barrier

Android中同步屏障的应用及简析