So you develop an Android app and you want to provide a smooth UI experience, part of this goal is running at a consistent 60 frames per second (why 60fps?) but how can you verify that you are doing it?.

Let me introduce to you the best friend for this mission the Choreographer, he responsible for Coordinates the timing of animations, input and drawing, but how does he do it?, The Choreographer has connections inside the Android system, every once in a while (the rumors saying 16.6 milliseconds) the choreographer receives timing pulses (VSYNC) from the display subsystem, as response the choreographer start to work on building the next frame that should be rendered, the pseudo code for this work look like this:

void doFrame(long frameTimeNanos, int frame) { ….. // handle input events InputHandling(); ….. // handle animation Animations(); ….. // measuring and drawing will take place here PerformTraversals(); ….. }

InputHandling will handle all touch event that happens on the screen and should be forward to the views, eventually, it will call to your on click listener or on touch event listener.

Animations will calculate the view’s new properties values, let’s assume that you animating the alpha property of view from 0 to 1, in each call to animations the view.alpha value will be changed according to the time that has being passed from the start of the animation, in case that you register an update listener to this animation, for example, every call to animation will end up calling to your listener.

PerformTraversals will do the view drawing work, including getting the view’s size when the view will be asked to measured, decide the view’s positions when the ViewGroup will be asked to layout its child views and call to draw that will record open GL commands that will be rendered later on the screen, any change in the view properties during animation stage will be reflected in this stage, if you have a custom view or custom view group your code will be called.

The choreographer doesn’t do all of this work by itself, it provides a way to register a callback that can be run upon any call to doFrame, those callbacks will run synchronously one by one, any delay in one of them will cause to increase the time that the choreographer spend in doFrame call.

ViewRootImpl register ConsumeBatchedInputImmediatelyRunnable callback in order to call to InputHandling, and it will register TraversalRunnable callback in order to call to PerformTraversals, AnimationHandler register AnimationFrameCallbackProvider callback to handle the animations.

To summarize it the choreographer get notification to start to build the next frame, as result the choreographer calls synchronously to callbacks that might eventually to call to your code, so if you do too much work there you might delay the choreographer from handling the next frame in time, or in another word 60 FPS meaning that the choreographer should call doFrame method 60 times in one second every second.

So how can you know what the choreographer is doing and how much time it’s taking him to do it?. First, you can look at the logcat for error that looks similar to this:



I/Choreographer: Skipped 555 frames! The application may be doing too much work on its main thread.

If you saw such error you can visually see the choreographer in action, all you need to do to run the systrace tool, the work of doFrame is already Surrounded with trace of Choreographer#doFrame

Valid Frame — less than 16.6 millisecond

So you can start checking whether you are doing too much work during a choreographer doFrame call. The systrace dump provides a lot of information for example in order to check whether you having a dropped frame you can look at Frames raw in the systrace dump:

The Frames row in systrace dump

Every green circle is good frame and every red circle is dropped frame, in case that you want to see why you drop this frame you might look at the corresponding choreographer raw and to see what happened there.

example for dropped frames

In this post I have introduced to you the choreographer and the correlation between him and 60 FPS, now you can verify whether you have dropping frames. In order to find the root cause of the lag, you might need to add some custom trace inside your code in order to guide you to the direct code that causes it but it’s a story for a different post.