Android Handlerメカニズムバリアメッセージ(同期バリア)


Handler Message種類
HandlerのMessageの種類は3種類あります.
  • 一般メッセージ
  • バリアメッセージ
  • 非同期メッセージ
  • ここで、一般的なメッセージは同期メッセージとも呼ばれ、バリアメッセージは同期バリアとも呼ばれる.
    バリアメッセージは通常、メッセージキューにバリアを挿入し、バリアの後のすべての一般メッセージが遮断され、処理できません.しかし、非同期メッセージは例外であり、バリアは非同期メッセージを遮断しないため、バリアメッセージは非同期メッセージの優先度を確保するためにバリアを設けた後、その後の非同期メッセージしか処理できず、バリアを取り消さない限り、同期メッセージは遮断されると考えられる.
    MeeageQueue
    メッセージ同期バリアはMeeageQueueで実装されています.次に、ソースコードがどのように作られているかを見てみましょう.
    一.メッセージバリアの追加
    private int postSyncBarrier(long when) {
            synchronized (this) {
                final int token = mNextBarrierToken++;
                //1、                   tartget。
                final Message msg = Message.obtain();
                msg.markInUse();
                msg.when = when;
                msg.arg1 = token;
    
                Message prev = null;
                Message p = mMessages;
                //2、                      
                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;
                }
                //3、      ,            
                return token;
            }
    }

    PostSyncBarrierメソッドはメッセージキューにバリアを挿入するために使用され、簡単であることがわかります.
    1バリアメッセージと一般メッセージの違いは、バリアにtartgetがないことであり、一般メッセージにtargetがあるのは、メッセージを対応するtargetに配布する必要があるためであり、バリアは配布する必要がなく、非同期メッセージの優先処理を保証するために一般メッセージを遮断するために使用されるためである.
    2バリアは、通常のメッセージと同様に、時間に応じてメッセージキュー内の適切な位置に挿入することができ、その後の同期メッセージの配布を遮断するだけである.
    3 postSyncBarrierはintタイプの値を返し、この値によってバリアを取り消すことができます.
    4 postSyncBarrierメソッドはプライベートであり、呼び出したい場合は反射を使用する必要があります.
    二.メッセージバリアの削除
    public void removeSyncBarrier(int token) {
                // Remove a sync barrier token from the queue.  
                //....  .......     barrier token  
                //    
                if (needWake && !mQuitting) {
                    nativeWake(mPtr);
                }
            }
        }

    メッセージバリアを削除して、次のことをしました.1.セカンダリシーケンス番号のtokenメッセージ2を削除する.プライマリ・スレッドがブロックされている場合は、スレッドを起動します.
    三メッセージバリアを取り出す
    MessageQueueはnextメソッドによってメッセージを取得することを知っています.
    Message next() {
        //1、                    ,    ,      。
        nativePollOnce(ptr, nextPollTimeoutMillis);
        synchronized (this) {
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {//2、      msg.target == null
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());//3、                 
            }
            if (msg != null) {
                //4、        
                if (now < msg.when) {//           ,    (    )
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    //          ,      ,   。
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                //              ,     。
                nextPollTimeoutMillis = -1;
            }
            //...
        }
    }

    同期バリアが設定されると、next関数はすべての同期メッセージを無視し、非同期メッセージを返すことがわかります.すなわち、同期バリアが設けられた後、Handlerは非同期メッセージのみを処理する.言い換えれば、同期バリアは、同期メッセージよりも非同期メッセージの優先度が高いHandlerメッセージメカニズムに単純な優先度メカニズムを追加する.
    非同期メッセージの送信方法
    通常、Handlerを使用してメッセージを送信する場合、これらのメッセージは同期メッセージであり、非同期メッセージを送信する場合は、Handlerを作成する際に次のコンストラクション関数のいずれかを使用します(async転送true)
    public Handler(boolean async);
    public Handler(Callback callback, boolean async);
    public Handler(Looper looper, Callback callback, boolean async);
    
  •  

  • Handlerを介して送信されたすべてのメッセージは非同期メッセージになります
    四同期バリアの応用
    Android4.1の後にChoreographerメカニズムが追加され、Vsyncメカニズムと組み合わせて、アニメーション、入力、描画タイミングを統一するために使用されます.
    ViewRootImplのrequestLayoutが描画プロセスを開始します.
    	@Override
        public void requestLayout() {
            if (!mHandlingLayoutInLayoutRequest) {
                checkThread();//        
                mLayoutRequested = true;//mLayoutRequested   measure layout  。
                //    
                scheduleTraversals();
            }
        }
    
  • はフレームワークの中でUIに応答するためにイベントを更新するためにViewRootImpl.scheduleTraversalsでは同期バリア
  • が使用されている
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            //      ,  mTraversalRunnable     
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            //    Handler         
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
    
  •  

  • mTraversalRunnableはperformTraversals実行measure,layout,drawを呼び出した
    mTraversalRunnableをできるだけ早く実行するために、メッセージを送信する前にMessageQueueを呼び出す.postSyncBarrierは同期バリアを設けた.