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信號對接上了