# Android Vitals - First draw time 👩🎨

DevFeed: [Android Vitals - First draw time 👩🎨](<https://devfeed.tech/articles/android-vitals-first-draw-time-25854.md>)

Original publisher: [Read original article](<https://dev.to/pyricau/android-vitals-first-draw-time-m1d>)

Author: Py ⚔

Published: 2020-08-29T11:51:28Z

Content type: tutorial

Language: en

Sources: [Py ⚔](<https://devfeed.tech/sources/py.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [Monitoring](<https://devfeed.tech/topics/monitoring.md>), [App](<https://devfeed.tech/topics/app.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [bug](<https://devfeed.tech/tags/bug.md>), [callback](<https://devfeed.tech/tags/callback.md>), [coding](<https://devfeed.tech/tags/coding.md>), [community](<https://devfeed.tech/tags/community.md>), [development](<https://devfeed.tech/tags/development.md>), [engineering](<https://devfeed.tech/tags/engineering.md>), [extension-function](<https://devfeed.tech/tags/extension-function.md>), [function](<https://devfeed.tech/tags/function.md>), [inclusive](<https://devfeed.tech/tags/inclusive.md>), [monitoring](<https://devfeed.tech/tags/monitoring.md>), [performance](<https://devfeed.tech/tags/performance.md>), [performance-monitoring](<https://devfeed.tech/tags/performance-monitoring.md>), [software](<https://devfeed.tech/tags/software.md>), [vitals](<https://devfeed.tech/tags/vitals.md>)

## AI overview

This article explains how Android app startup time is tied to the first completely loaded frame and focuses on measuring when cold start ends. It compares Choreographer.postFrameCallback() with ViewTreeObserver.addOnDrawListener(), describing timing behavior, an API 25 issue, and an API 26 listener-merging bug workaround.

## Source excerpt

Header image: Light Field by Romain Guy. This blog series is focused on stability and performance monitoring of Android apps in production. Last week, I wrote about how to best determine the app start time. Today, we focus on determining the time at which cold start ends. According to the Play Console documentation: Startup times are tracked when the app's first frame completely loads. We learn a bit more from the App startup cold time documentation: Once the app process has completed the first draw, the system process swaps out the currently displayed background window, replacing it with the main activity. At this point, the user can start using the app. In Android Vitals - Rising to the first drawn surface 🤽♂, we learnt that: ActivityThread.handleResumeActivity() schedules the first frame. On the first frame Choreographer.doFrame() calls ViewRootImpl.doTraversal() which performs a measure pass, a layout pass, and finally the first draw pass on the view hierarchy. First frame Since API level 16, Android provides a simple API to schedule a callback when the next frame happens: Choreographer.postFrameCallback(). class MyApp : Application() { var firstFrameDoneMs: Long = 0 override fun onCreate() { super.onCreate() Choreographer.getInstance().postFrameCallback { firstFrameDoneMs = SystemClock.uptimeMillis() } } } Unfortunately, calling Choreographer.postFrameCallback() has the side effect of scheduling a frame that runs before the first traversal is scheduled. So the time reported here is before the time of the frame that runs the first draw. I was able to reproduce this on API 25 but also noticed it doesn't happen in API 30, so this bug was probably fixed. First draw ViewTreeObserver On Android, each view hierarchy has a ViewTreeObserver which can hold callbacks for global events such as layout or draw. ViewTreeObserver.addOnDrawListener() We can call ViewTreeObserver.addOnDrawListener() to register a draw listener: view.viewTreeObserver.addOnDrawListener { // repo