> Java > java지도 시간 > Java 핸들러 동기화 장벽 예제 코드 분석

Java 핸들러 동기화 장벽 예제 코드 분석

WBOY
풀어 주다: 2023-05-03 18:52:07
앞으로
901명이 탐색했습니다.

1. View의 로딩과 드로잉 과정에는 mChoreographer라는 안무가 클래스가 있습니다.

mTraversalBarrier = mHandler.getLooper().postSyncBarrier(); MessageQueue, msg.target==null 메시지에 동기화 장벽 메시지를 삽입합니다. 반환 값 mTraversalBarrier는 int 토큰 값입니다. mTraversalBarrier = mHandler.getLooper().postSyncBarrier();向MessageQueue中插入一条同步屏障消息,msg.target==null的消息,返回值mTraversalBarrier是一个int 的token值。

  void scheduleTraversals() {
    if (!mTraversalScheduled) {
      mTraversalScheduled = true;
       //向消息队列插入一个同步屏障的消息。msg.target==null的消息
             mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
             mChoreographer.postCallback(
                  Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    }
  }
로그인 후 복사

mChoreographer.postCallback()方法会执行mTraversalRunnable中的代码。

mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);

 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
 final class TraversalRunnable implements Runnable {
            @Override
            public void run() {
                doTraversal();
            }
  }
   void doTraversal() {
      if (mTraversalScheduled) {
          mTraversalScheduled = false;
          //移除同步屏障消息
          mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
          //在这个方法中会调用 measure layout draw,view的绘制绘制流程的方法
          performTraversals();
      }
    }
로그인 후 복사

mChoreographer.postCallback() 메소드는 mTraversalRunnable의 코드를 실행합니다.

mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);위에서 생성된 토큰 값을 기반으로 MessageQueue의 동기화 장벽 메시지를 제거합니다.

int enqueueSyncBarrier(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++;
            // 这个msg.target没有被赋值
            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) { // invariant: p == prev.next
                msg.next = p;
                prev.next = msg;
            } else {
                msg.next = p;
                mMessages = msg;
            }
            return token;
        }
    }
로그인 후 복사

시스템이 이를 어떻게 처리하는지 보려면 mHandler.getLooper().postSyncBarrier() 코드 줄을 보세요.

핸들러가 설정되지 않은 메시지를 받았습니다.

 boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
   ...........
}
로그인 후 복사

일반적으로 우리는 핸들러를 통해 메시지를 보내며, 핸들러는 비워둘 수 없습니다.

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 {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                //将消息设置为异步消息
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
}
로그인 후 복사

그렇다면 시스템은 왜 빈 핸들러로 메시지를 보내는 걸까요?

먼저 mChoreographer가 동기화 장벽 메시지를 보낸 후 무엇을 했는지 살펴볼까요?

또 다른 비동기 메시지가 전송되었습니다: msg.setAsynchronous(true). 이 메시지의 핸들러는 null이 아닙니다.

 Message next() {
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                //如果msg.target==null说明我们已经向消息队里中插入了一条屏障消息。
                //此时会进入到这个循环中,找到msg.isAsynchronous==true的异步消息。
                //通常我们发送的都是同步消息isAsynchronous = false的,并且msg.target不能为null的。
                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());//msg.isAsynchronous==true时结束循环,说明找到了这个异步消息。
                }
                if (msg != null) {//找到了同步屏障的异步消息后,直接返回
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
                        return msg;
                    }
                } else {//没有找到的话则进入休眠直到下一次被唤醒
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }
        }
    }
로그인 후 복사
다음으로 MessageQueue가 메시지를 보내는 방법과 이 동기화 장벽 메시지를 처리하는 방법을 살펴보겠습니다.

rrreee

취소할 때는 먼저 msg.target이 null인지 확인한 다음 while 루프를 거쳐 msg.isAsynchronous() == true라는 메시지를 찾습니다. 이것이 위에서 보낸 비동기 메시지입니다. 일반적으로 우리가 보내는 메시지는 동기 메시지이며 msg.setAsynchronous(true)는 설정되지 않습니다.

시스템의 목적은 이 비동기 메시지를 먼저 처리하는 것입니다. 모든 동기화 메시지는 배리어처럼 뒤쪽에 배치되므로 이러한 작업을 동기화 배리어라고 하며 동기화 배리어 메시지의 처리 우선순위가 더 높습니다. 🎜🎜안무가 클래스 mChoreographer는 화면 렌더링을 담당하므로 인터페이스 새로 고침 빈도를 보장하기 위해 적시에 하위 레이어의 신호를 처리해야 합니다. 🎜

위 내용은 Java 핸들러 동기화 장벽 예제 코드 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:yisu.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿