# vitals

Published articles for vitals.

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## Preparing your app for broader memory limits

DevFeed: [Preparing your app for broader memory limits](<https://devfeed.tech/articles/preparing-your-app-for-broader-memory-limits-22689.md>)

Original publisher: [Read original article](<http://android-developers.googleblog.com/2026/08/app-broader-memory-limits.html>)

Author: Android Developers (noreply@blogger.com)

Published: 2026-08-19T19:00:00Z

Content type: tutorial

Language: en

Sources: [Android Developers Blog](<https://devfeed.tech/sources/android-developers-blog-3.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [User Experience](<https://devfeed.tech/topics/user-experience.md>), [Memory Leaks](<https://devfeed.tech/topics/memory-leaks.md>), [memory price increases](<https://devfeed.tech/topics/memory-price-increases.md>)

Tags: [adb](<https://devfeed.tech/tags/adb.md>), [android](<https://devfeed.tech/tags/android.md>), [memory-leaks](<https://devfeed.tech/tags/memory-leaks.md>), [memory-optimization](<https://devfeed.tech/tags/memory-optimization.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [user-experience](<https://devfeed.tech/tags/user-experience.md>), [vitals](<https://devfeed.tech/tags/vitals.md>)

### AI overview

This Android Developers article explains how Android 17 per-app memory limits are expanding beyond Pixel devices across a range of RAM configurations. It describes the effects of exceeding memory budgets, including zRAM swapping, CPU overhead, UI jank, throttling, and possible process termination, and outlines ways to measure and optimize app memory usage.

### Source excerpt

Posted by Blair Harmon, Director of Product Management, Android Platform A great user experience is central to Android's mission, and delivering on that promise requires keeping devices fast, responsive, and reliable. This is why memory optimization is more critical than ever. Across the ecosystem, new devices are maintaining or even decreasing their physical memory capacity in response to memory price increases, yet users continue to expect the same seamless, high-performance app experience. In Android 17, we introduced per-app memory limits, starting with Pixel devices, to help protect the overall user experience from applications using excess memory and causing system-wide slowdowns. Over the coming year, an increasing number of manufacturers will leverage the Android per-app memory limits across their portfolio of device RAM configurations from 4GB to 16GB+ devices. If your app exceeds these limits, it will be slowed down and may be terminated. Optimizing your app's memory footprint is essential to preventing OS throttling and maintaining a seamless user experience. In this post, we'll explore how these limits work under the hood, how to measure your memory footprint using new Android vitals metrics, and actionable steps to optimize your app or game. Understanding Memory Limits When your app exceeds its memory budget, Android takes progressive action to protect device responsiveness: zRAM Swapping: If your app reaches its allocated limit, the system forces your app's pages into zRAM (compressed RAM). While zRAM prevents immediate eviction, compressing and decompressing pages adds CPU overhead, which can result in noticeable UI jank and experience slowdowns. Process Termination: If your app continues to increase its memory usage beyond the zRAM threshold, it will be terminated by the system. To determine if your app session was impacted by these constraints in the field, you can call getDescription() within ApplicationExitInfo. If the system applied a limit, the

## Android Vitals - Tap Response Time 👉

DevFeed: [Android Vitals - Tap Response Time 👉](<https://devfeed.tech/articles/android-vitals-tap-response-time-25858.md>)

Original publisher: [Read original article](<https://dev.to/pyricau/android-vitals-tap-response-time-19mj>)

Author: Py ⚔

Published: 2021-04-15T14:10:20Z

Content type: tutorial

Language: en

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

Topics: [Android](<https://devfeed.tech/topics/android.md>), [User experience (UX)](<https://devfeed.tech/topics/ux.md>), [navigation](<https://devfeed.tech/topics/navigation.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [code](<https://devfeed.tech/tags/code.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>), [inclusive](<https://devfeed.tech/tags/inclusive.md>), [monitoring](<https://devfeed.tech/tags/monitoring.md>), [navigation](<https://devfeed.tech/tags/navigation.md>), [performance](<https://devfeed.tech/tags/performance.md>), [software](<https://devfeed.tech/tags/software.md>), [ux](<https://devfeed.tech/tags/ux.md>), [vitals](<https://devfeed.tech/tags/vitals.md>)

### AI overview

This article defines Tap Response Time on Android as the interval between a finger leaving the touchscreen and the display rendering a frame that visibly reacts to the tap. It examines a naive measureTimeMillis() approach and explains why it can produce negative or incomplete measurements and does not scale across a codebase.

### Source excerpt

Header image: Alone Together by Romain Guy. Android users expect apps to respond to their actions within a short time window. 💡 Did you know? UX research teaches us that a response time shorter than 100ms feels immediate, and a response time beyond 1s makes users lose focus. When the response time gets closer to 10 seconds, users simply abandon their task (source). 👉📱 Measuring user action response times is critical to ensure a good user experience. Taps are the most common action apps must respond to. Can we measure Tap Response Time? 🎓 Tap Response Time The Tap Response Time is the time from when the user is done pressing a button to when the app has visibly reacted to the tap. More precisely, it's the time from when the finger leaves the touch screen to when the display has rendered a frame with a visible reaction to that tap (e.g. the start of a navigation animation). The Tap Response Time does not include any animation time. Naive Tap Response Time I opened the Navigation Advanced Sample project and added a call to measureTimeMillis() to measure the Tap Response Time when tapping on the about button. aboutButton.setOnClickListener { val tapResponseTimeMs = measureTimeMillis { findNavController().navigate(R.id.action_title_to_about) } PerfAnalytics.logTapResponseTime(tapResponseTimeMs) } Simple enough! However this approach presents several drawbacks: ⌛ It can return a negative time. 📈 It doesn't scale with the codebase size. 👉 It doesn't account for the time from when the finger leaves the touch screen to when the click listener is called. 📱 It doesn't account for the time from when we're done calling NavController.navigate() to when the display has rendered a frame with the new screen visible. ⌛ Negative time measureTimeMillis() calls System.currentTimeMillis() whihch can be set by the user or the phone network, so the time may jump backwards or forwards unpredictably. Elapsed time measurements should not use System.currentTimeMillis() (learn more: Android V

## 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

## Android Vitals - When did my app start? ⏱

DevFeed: [Android Vitals - When did my app start? ⏱](<https://devfeed.tech/articles/android-vitals-when-did-my-app-start-25859.md>)

Original publisher: [Read original article](<https://dev.to/pyricau/android-vitals-when-did-my-app-start-24p4>)

Author: Py ⚔

Published: 2020-08-21T21:01:05Z

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>), [Processes](<https://devfeed.tech/topics/processes.md>)

Tags: [android](<https://devfeed.tech/tags/android.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>), [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>), [process](<https://devfeed.tech/tags/process.md>), [software](<https://devfeed.tech/tags/software.md>), [vitals](<https://devfeed.tech/tags/vitals.md>)

### AI overview

This Android Vitals article evaluates several ways to determine when an Android app starts, including Application.onCreate(), ContentProvider.onCreate(), class loading, and Linux process start time. It explains why process fork time may precede the meaningful beginning of app cold-start monitoring.

### Source excerpt

Header image: Ressence Type 5 Tilt by Romain Guy. This blog series is focused on stability and performance monitoring of Android apps in production. Last week, I wrote about using process importance to determine why an app was started. To track cold start time, we need to know when the app started. There are many ways to do that and this blog evaluates different approaches. As a reminder, I already established in Android Vitals - What time is it? that I would use SystemClock.uptimeMillis() to measure time intervals. Application.onCreate() The simplest approach is to capture the time at which Application.onCreate() is called. class MyApp : Application() { var applicationOnCreateMs: Long = 0 override fun onCreate() { super.onCreate() applicationOnCreateMs = SystemClock.uptimeMillis() } } ContentProvider.onCreate() In How does Firebase initialize on Android? we learn that a safe early initialization hook for library developers is ContentProvider.onCreate(): class StartTimeProvider : ContentProvider() { var providerOnCreateMs: Long = 0 override fun onCreate(): Boolean { providerOnCreateMs = SystemClock.uptimeMillis() return false } } ContentProvider.onCreate() also works for app developers and it's called earlier in the app lifecycle than Application.onCreate(). Class load time Before any class can be used, it has to be loaded. We can rely on static initializers to store the time at which specific classes are loaded. We could track the time at which the Application class is loaded: class MyApp : Application() { companion object { val applicationClassLoadMs = SystemClock.uptimeMillis() } } In Android Vitals - Diving into cold start waters 🥶, we learnt that on Android P+ the first class loaded is the AppComponentFactory: @RequiresApi(Build.VERSION_CODES.P) class StartTimeFactory : androidx.core.app.AppComponentFactory() { companion object { val factoryClassLoadMs = SystemClock.uptimeMillis() } } <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schema

## Android Vitals - Why did my process start? 🌄

DevFeed: [Android Vitals - Why did my process start? 🌄](<https://devfeed.tech/articles/android-vitals-why-did-my-process-start-25860.md>)

Original publisher: [Read original article](<https://dev.to/pyricau/android-vitals-why-did-my-process-start-4d0e>)

Author: Py ⚔

Published: 2020-08-15T14:06:06Z

Content type: tutorial

Language: en

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

Topics: [Android](<https://devfeed.tech/topics/android.md>), [Processes](<https://devfeed.tech/topics/processes.md>), [Process](<https://devfeed.tech/topics/process.md>), [Monitoring](<https://devfeed.tech/topics/monitoring.md>)

Tags: [android](<https://devfeed.tech/tags/android.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>), [inclusive](<https://devfeed.tech/tags/inclusive.md>), [lifecycle](<https://devfeed.tech/tags/lifecycle.md>), [memory](<https://devfeed.tech/tags/memory.md>), [monitoring](<https://devfeed.tech/tags/monitoring.md>), [performance](<https://devfeed.tech/tags/performance.md>), [performance-monitoring](<https://devfeed.tech/tags/performance-monitoring.md>), [process](<https://devfeed.tech/tags/process.md>), [processes](<https://devfeed.tech/tags/processes.md>), [software](<https://devfeed.tech/tags/software.md>), [vitals](<https://devfeed.tech/tags/vitals.md>)

### AI overview

This article explains how Android process importance can help identify cold starts when the reason a process started is unavailable through an Android API. It describes checking RunningAppProcessInfo.importance via ActivityManager.getMyMemoryState() at process startup and reports anonymized production results comparing startup importance with whether an activity was created before the first posted message.

### Source excerpt

Header image: Windmill Sunrise 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 determine if an app start is a cold start: If we post a message and no activity was created when that message runs, then we know this isn't a cold start, even if an activity is eventually launched 20 seconds later. class MyApp : Application() { override fun onCreate() { super.onCreate() var firstActivityCreated = false registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { override fun onActivityCreated( activity: Activity, savedInstanceState: Bundle? ) { if (firstActivityCreated) { return } firstActivityCreated = true } }) Handler().post { if (firstActivityCreated) { // TODO Report cold start } } } } With this approach, we must wait for an activity to be launched or that message to run before we know if an app start is a cold start. Sometimes it would be useful to know that from within Application.onCreate(). For example, we might want to preload resources asynchronously to optimize cold start: class MyApp : Application() { override fun onCreate() { super.onCreate() if (isColdStart()) { preloadDataForUiAsync() } } } Process importance While there is no Android API to know why a process was started, there is one to know why a process is still running: RunningAppProcessInfo.importance, which we can read from ActivityManager.getMyMemoryState(). According to the Processes and Application Lifecycle documentation: To determine which processes should be killed when low on memory, Android places each process into an "importance hierarchy" based on the components running in them and the state of those components. [...] When deciding how to classify a process, the system will base its decision on the most important level found among all the components currently active in the process. Right when the process starts, we could check its importance. If the importance is IMPORTANCE_FOREGRO

## Android Vitals - Is this a cold start? 🦋

DevFeed: [Android Vitals - Is this a cold start? 🦋](<https://devfeed.tech/articles/android-vitals-is-this-a-cold-start-25856.md>)

Original publisher: [Read original article](<https://dev.to/pyricau/android-vitals-is-this-a-cold-start-3m44>)

Author: Py ⚔

Published: 2020-08-05T22:00:07Z

Content type: article

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>), [Processes](<https://devfeed.tech/topics/processes.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [code](<https://devfeed.tech/tags/code.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>), [inclusive](<https://devfeed.tech/tags/inclusive.md>), [monitoring](<https://devfeed.tech/tags/monitoring.md>), [performance](<https://devfeed.tech/tags/performance.md>), [process](<https://devfeed.tech/tags/process.md>), [software](<https://devfeed.tech/tags/software.md>), [vitals](<https://devfeed.tech/tags/vitals.md>)

### AI overview

This article explains cold starts in Android apps and why Android does not provide a direct API to identify them. It discusses monitoring cold-start times in production and begins developing an alternative detection approach based on app and activity lifecycle behavior.

### Source excerpt

Header image: Follow the Light by Romain Guy. This blog series is focused on stability and performance monitoring of Android apps in production. In the last 2 posts, I wrote about what happens from when the user taps a launcher icon to when the first activity is drawn. A cold start is an activity launch where the app process starts from scratch in response to an intent to start an activity. According to the App startup time documentation: This type of start presents the greatest challenge in terms of minimizing startup time, because the system and app have more work to do than in the other launch states. We recommend that you always optimize based on an assumption of a cold start. Doing so can improve the performance of warm and hot starts, as well. To optimize cold start, we need to measure it, which means we need to monitor cold start times in production. Unfortunately, there is no Activity.isThisAColdStart() API on Android. This is by design: the Activity lifecycle APIs indicate when to save and restore state and abstract away the death and rebirth of processes. The engineers who designed the Android APIs didn't want us to write overly complex code with special cases for all the various ways an activity can be started. So there's no API. How are we supposed to monitor cold start if we can't tell a cold start from any other process start? This post leverages what we learnt from our previous deep dives on cold start to start building out our own version of the missing Activity.isThisAColdStart() API. Traditional approach Most apps and libraries report a cold start if the first activity was created within a minute of the app start. It looks something like this: class MyApp : Application() { override fun onCreate() { super.onCreate() val appCreateMs = SystemClock.uptimeMillis() var firstActivityCreated = false registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { override fun onActivityCreated( activity: Activity, savedInstanceState: Bundle? ) { if