Android界面顯示_視圖Choreographer控制

Android界面顯示_視圖Choreographer控制

  • GPU/CPU生產幀率和屏幕消費幀率的生產者消費者模式

  • 掉幀,雙緩存,三緩存

  • SurfaceFlinger進程發出vsync信號

  • Choreographer(ThreadLocal持有,即ui線程持有)負責獲取Vsync同步信號並控制App線程(主線程)完成圖像繪製的類

  • 主線程中初始化變量時,創建Choreographer對象,綁定主線程Looper

  • Choreographer通過DisplayEventReceiver通過JNI調用,利用Binder機制接收surfaceflinger進程底層Vsync信號,請求幀畫面顯示控制。在需要繪製時,發起請求。底層初始化(nativeInit),發起請求(scheduleVsync),實現回調(dispatchVsync)

  • DisplayEventReceiver收到底層各種類型的信號,在doFrame()方法中處理doCallbacks(int callbackType, long frameTimeNanos)

    void doFrame(long frameTimeNanos, int frame) {
      ...
    try {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
                AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
    
                mFrameInfo.markInputHandlingStart();
                doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
    
                mFrameInfo.markAnimationsStart();
                doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
                doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
    
                mFrameInfo.markPerformTraversalsStart();
                doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
    
                doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
            } finally {
                AnimationUtils.unlockAnimationClock();
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
      ...
    }
    
  • callbackType類型:

    • Choreographer.CALLBACK_INPUT(控制同步處理輸入Input)
    • Choreographer.CALLBACK_ANIMATION(控制同步動畫Animation)
    • Choreographer.CALLBACK_TRAVERSAL(觸發ViewRootImpl的doTraversal方法,實現一次遍歷繪製)
    • Choreographer.CALLBACK_INSETS_ANIMATION
    • Choreographer.CALLBACK_COMMIT(遍歷完成的提交操作,用來修正動畫啓動時間)
  • 自定義doFrame監聽每一幀渲染時間,獲取設備當前幀率(開源項目:Tiny Dancer)

    Choreographer.getInstance().postFrameCallback(new FPSFrameCallback());
    
    public class FPSFrameCallback implements Choreographer.FrameCallback{
    @Override
      public void doFrame(long frameTimeNanos){
          //do something
      }
    
    
  • doCallbacks代碼如下:

    void doCallbacks(int callbackType, long frameTimeNanos) {
            CallbackRecord callbacks;
            synchronized (mLock) {
                // We use "now" to determine when callbacks become due because it's possible
                // for earlier processing phases in a frame to post callbacks that should run
                // in a following phase, such as an input event that causes an animation to start.
                final long now = System.nanoTime();
                callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                        now / TimeUtils.NANOS_PER_MS);
                if (callbacks == null) {
                    return;
                }
                mCallbacksRunning = true;
    
                // Update the frame time if necessary when committing the frame.
                // We only update the frame time if we are more than 2 frames late reaching
                // the commit phase.  This ensures that the frame time which is observed by the
                // callbacks will always increase from one frame to the next and never repeat.
                // We never want the next frame's starting frame time to end up being less than
                // or equal to the previous frame's commit frame time.  Keep in mind that the
                // next frame has most likely already been scheduled by now so we play it
                // safe by ensuring the commit time is always at least one frame behind.
                if (callbackType == Choreographer.CALLBACK_COMMIT) {
                    final long jitterNanos = now - frameTimeNanos;
                    Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
                    if (jitterNanos >= 2 * mFrameIntervalNanos) {
                        final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
                                + mFrameIntervalNanos;
                        if (DEBUG_JANK) {
                            Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
                                    + " ms which is more than twice the frame interval of "
                                    + (mFrameIntervalNanos * 0.000001f) + " ms!  "
                                    + "Setting frame time to " + (lastFrameOffset * 0.000001f)
                                    + " ms in the past.");
                            mDebugPrintNextFrameTimeDelta = true;
                        }
                        frameTimeNanos = now - lastFrameOffset;
                        mLastFrameTimeNanos = frameTimeNanos;
                    }
                }
            }
            try {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
                for (CallbackRecord c = callbacks; c != null; c = c.next) {
                    if (DEBUG_FRAMES) {
                        Log.d(TAG, "RunCallback: type=" + callbackType
                                + ", action=" + c.action + ", token=" + c.token
                                + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
                    }
                    c.run(frameTimeNanos);
                }
            } finally {
                synchronized (mLock) {
                    mCallbacksRunning = false;
                    do {
                        final CallbackRecord next = callbacks.next;
                        recycleCallbackLocked(callbacks);
                        callbacks = next;
                    } while (callbacks != null);
                }
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
        }
    

    從mCallbackQueues中取出CallbackRecord,for循環遍歷執行c.run(frameTimeNanos);

  • CallbackRecord代碼如下:

        private static final class CallbackRecord {
            public CallbackRecord next;
            public long dueTime;
            public Object action; // Runnable or FrameCallback
            public Object token;
    
            @UnsupportedAppUsage
            public void run(long frameTimeNanos) {
                if (token == FRAME_CALLBACK_TOKEN) {
                    ((FrameCallback)action).doFrame(frameTimeNanos);
                } else {
                    ((Runnable)action).run();
                }
            }
        }
    

    CallbackRecord的run方法中((Runnable)action).run();

  • CallbackRecord對象中的(Runnable)action是我們在ViewRootImpl類當中的InvalidateOnAnimationRunnable、mConsumedBatchedInputRunnable、mTraversalRunnable添加到Choreographer中來的。那麼回到View的流程中,比如收到Vsync信號後,就會回調mTraversalRunnable的run()方法,再次發起一次measure、layout、draw流程,那麼也就和Vsync信號對接上了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章