Almost everyone developing an Android app has seen something like this in their device logs.

Bash
1
I/Choreographer(1200): Skipped 60 frames!  The application may be doing too much work on its main thread.

On most devices, the Android platform tries to render a new frame every 16 milliseconds (60 fps).   The rendering requires that whatever work is happening on the UI thread should finish in that timeframe (well, actually in less than that). Any unit of work (== Runnable) scheduled on the UI thread has to fit in that. When the work takes longer, then frames are skipped. One skipped frame is 16 ms of the hung screen. The UI looks janky and unresponsive and if the user interacts with the screen and the application does not respond in time ( 5 seconds) then Application Not Responding (ANR) shows up.

Another interesting scenario where the work can take longer is when the work involves acquiring a lock (for example, for executing synchronized code). Any synchronized code on the main thread is almost always a bad idea since you have no control over who could be holding the lock. And the developer writing the code to run on a background thread has no idea that holding a particular lock can cause any problems. Android has two tools to debug this. One of them is dumpsys for the statistical info; the other one is Method profiling via Android Device Monitor for identifying the culprits.

Bash
1
2
3
4
5
6
7
$ adb shell dumpsys gfxinfo com.google.android.gm
...
Janky frames: 10337 (12.37%)
90th percentile: 17ms
95th percentile: 25ms
99th percentile: 69ms
...

And, by the way, Choreographer is the class that does the actual rendering work.