Users expect apps to be responsive and fast to load. An app with a slow start time doesn't meet this expectation and can disappoint users. This sort of poor experience can cause a user to rate your app poorly on the Play store or even abandon your app altogether.
This page provides information to help optimize your app's launch time, including an overview of the internals of the launch process, how to profile startup performance, and some common start-time issues with tips on how to address them.
Understand the different app startup states
App launch can take place in one of three states: cold start, warm start, or hot start. Each state affects how long it takes for your app to become visible to the user. In a cold start, your app starts from scratch. In the other states, the system needs to bring the running app from the background to the foreground.
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 your app for fast startup, it's useful to understand what's happening at the system and app levels and how they interact in each of these states.
Two important metrics for determining app startup are time to initial display (TTID) and time to fully drawn (TTFD). TTID is the time taken to display the first frame, and TTFD is the time taken for the app to become fully interactive. Both are equally important, as TTID lets the user know that the app is loading, and TTFD is when the app is actually useable. If either of these is too long, the user might exit your app before it even fully loads.
To get accurate values for TTFD, signal when the app reaches a fully drawn state to help ensure accurate times are measured. To learn how to do this, see Improving startup timing accuracy.
Cold start
A cold start refers to an app's starting from scratch. This means that until this start, the system's process creates the app's process. Cold starts happen in cases such as your app launching for the first time since the device booted or since the system killed the app.
This type of start presents the greatest challenge to minimizing startup time, because the system and app have more work to do than in the other launch states.
At the beginning of a cold start, the system has the three following tasks:
- Load and launch the app.
- Display a blank starting window for the app immediately after launch.
- Create the app process.
As soon as the system creates the app process, the app process is responsible for the next stages:
- Create the app object.
- Launch the main thread.
- Create the main activity.
- Inflate views.
- Layout the screen.
- Perform the initial draw.
When the app process completes the first draw, the system process swaps out the displayed background window, replacing it with the main activity. At this point, the user can start using the app.
Figure 1 shows how the system and app processes hand off work between each other.

Performance issues can arise during creation of the app and creation of the activity.
App creation
When your app launches, the blank starting window remains on the screen until the system finishes drawing the app for the first time. At this point, the system process swaps the starting window for your app, letting the user interact with the app.
If you override
Application.onCreate()
in
your own app, the system invokes the onCreate()
method on your app object.
Afterwards, the app spawns the main thread, also known as the UI thread, and
tasks it with creating your main activity.
From this point, system- and app-level processes proceed in accordance with the app lifecycle stages.
Activity creation
After the app process creates your activity, the activity performs the following operations:
- Initializes values.
- Calls constructors.
- Calls the callback method, such as
Activity.onCreate()
, appropriate to the current lifecycle state of the activity.
Typically, the
onCreate()
method has the greatest impact on load time, because it performs the work with
the highest overhead: loading and inflating views and initializing the objects
needed for the activity to run.
Warm start
A warm start encompasses a subset of the operations that take place during a cold start. At the same time, it represents more overhead than a hot start. There are many potential states that can be considered warm starts, such as the following:
The user backs out of your app but then re-launches it. The process might continue to run, but the app must recreate the activity from scratch using a call to
onCreate()
.The system evicts your app from memory and then the user re-launches it. The process and the activity needs to restart, but the task can benefit somewhat from the saved instance state bundle passed into
onCreate()
.
Hot start
A hot start of your app has lower overhead than a cold start. In a hot start, the system brings your activity to the foreground. If all of your app's activities are still resident in memory, then the app can avoid repeating object initialization, layout inflation, and rendering.
However, if some memory is purged in response to memory trimming events, such as
onTrimMemory()
, then these objects need to be recreated in response to
the hot start event.
A hot start displays the same on-screen behavior as a cold start scenario. The system process displays a blank screen until the app finishes rendering the activity.
How to identify app startup in Perfetto
To debug app startup issues, it's helpful to determine what exactly is included in the app startup phase. To identify the entire app startup phase in Perfetto, follow these steps:
In Perfetto, find the row with the Android App Startups derived metric. If you don't see it, try capturing a trace using the on-device system tracing app.
Figure 3.The Android App Startups derived metric slice in Perfetto. Click the associated slice and press m to select the slice. Brackets appear around the slice and denote how long it took. The duration is also shown in the Current selection tab.
Pin the Android App Startups row by clicking on the pin icon, which is visible when you hold the pointer over the row.
Scroll down to the row with the app in question and click the first cell to expand the row.
Zoom into the main thread, usually at the top, by pressing w (press s, a, d to zoom out, move left, and move right, respectively).
Figure 4.The Android App Startups derived metric slice next to the main thread of the app. The derived metrics slice makes it easier to see what exactly is included in the app startup, so you can continue to debug in more detail.
Use metrics to detect and diagnose problems
To properly diagnose startup time performance, you can track metrics that show how long it takes your app to start. Android provides several means of showing you that your app has a problem and helps you diagnose it. Android vitals can alert you that a problem is occurring, and diagnostic tools can help you diagnose the problem.
Benefits of utilizing startup metrics
Android uses the time to initial display (TTID) and time to
full display (TTFD) metrics to optimize cold and warm app startups.
Android Runtime (ART) uses the data from these metrics to efficiently precompile
code for optimization of future startups.
Faster startups lead to more sustained user interaction with your app, which reduces instances of early exiting, restarting the instance, or navigating away to a different app.
Android vitals
Android vitals can help improve your app's performance by alerting you on the Play Console when your app's startup times are excessive.
Android vitals considers the following startup times for your app excessive:
- Cold startup takes 5 seconds or longer.
- Warm startup takes 2 seconds or longer.
- Hot startup takes 1.5 seconds or longer.
Android vitals uses the time to initial display (TTID) metric. For information about how Google Play collects Android vitals data, see the Play Console documentation.
Time to initial display
The time to initial display (TTID) metric measures the time it takes for an app to produce its first frame, including process initialization during a cold start, activity creation during a cold or warm start, and displaying first frame.
How to retrieve TTID
Logcat includes an output line containing a value called
Displayed
. This value represents the amount of time elapsed between launching
the process and finishing drawing the corresponding activity on the screen. The
elapsed time encompasses the following sequence of events:
- Launch the process.
- Initialize the objects.
- Create and initialize the activity.
- Inflate the layout.
- Draw your app for the first time.
The reported log line looks similar to the following example:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms
If you're tracking logcat output from the command line or in a terminal, finding the elapsed time is straightforward. To find elapsed time in Android Studio, disable the filters in your logcat view. Disabling the filters is necessary because the system server, not the app itself, serves this log.
After you make the appropriate settings, you can search for the correct term
to see the time. Figure 3 shows how to disable filters by selecting "No
filters" from the folier drop-down, and in the second line of output from the
bottom, an example of logcat output of the Displayed
time.

Displayed
value in logcat.The Displayed
metric in the logcat output doesn't necessarily capture the
amount of time until all resources are loaded and displayed. It leaves out
resources that aren't referenced in the layout file or that the app creates as
part of object initialization. It excludes these resources because loading them
is an inline process and it doesn't block the app's initial display.
Sometimes the Displayed
line in the logcat output contains an additional field
for total time. For example:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)
In this case, the first time measurement is only for the activity that is first
drawn. The total
time measurement begins at the app process start and can
include another activity that is started first but doesn't display anything to
the screen. The total
time measurement is only shown when there is a
difference between the single activity and total startup times.
You can also measure the TTID by running your app with the ADB Shell Activity Manager command. Here's an example:
adb [-d|-e|-s <serialNumber>] shell am start -S -W
com.example.app/.MainActivity
-c android.intent.category.LAUNCHER
-a android.intent.action.MAIN
The Displayed
metric appears in the logcat output as before. Your terminal
window displays the following:
Starting: Intent
Activity: com.example.app/.MainActivity
ThisTime: 2044
TotalTime: 2044
WaitTime: 2054
Complete
The -c
and -a
arguments are optional and let you specify
<category>
and
<action>
.
Time to full display
The time to full display (TTFD) metric measures the time taken by the app to produce its first frame with full content, including content loaded asynchronously after the first frame. Generally, this is primary list content loaded from the network, as reported by the app.
How to retrieve TTFD
You can use the
reportFullyDrawn()
method to measure the elapsed time between app launch and the complete
display of all resources and view hierarchies. This can be valuable in cases
where an app performs lazy loading. In lazy loading, an app doesn't block the
initial drawing of the window but instead asynchronously loads resources and
updates the view hierarchy.
Due to lazy loading, if an app's initial display doesn't include all resources, you might consider the completed loading and display of all resources and views as a separate metric. For example, your UI might be fully loaded with some text drawn, but it might not yet display images that the app must fetch from the network.
Improve startup timing
accuracy
explains how to use
FullyDrawnReporter
to delay
calling
reportFullyDrawn
until after your app becomes interactive to the user.
When you use this API, the value that logcat displays is the time elapsed from
the creation of the app object to the moment reportFullyDrawn()
is called.
Here's an example of the logcat output:
system_process I/ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms
The logcat output sometimes includes a total
time, as discussed in Time to
initial display.
If you learn that your display times are slower than you want, you can try to identify the bottlenecks in the startup process.
Identify bottlenecks
To look for bottlenecks, you can use the Android Studio CPU Profiler. For more information, see Inspect CPU activity with CPU Profiler.
You can also gain insight into potential bottlenecks through inline tracing
inside of your apps' and activities' onCreate()
methods. To learn about inline
tracing, see the documentation for the Trace
functions and the overview of system tracing.
Solve common issues
This section discusses several issues that often affect app startup performance. These issues mainly concern initializing app and activity objects, as well as the loading of screens.
Heavy app initialization
Launch performance can suffer when your code overrides the Application
object
and executes heavy work or complex logic when initializing that object. Your app
might waste time during startup if your Application
subclasses perform
initializations that don't need to be done yet.
Some initializations might be completely unnecessary, such as when initializing state information for the main activity when the app is actually started up in response to an intent. With an intent, the app uses only a subset of the previously initialized state data.
Other challenges during app initialization include garbage collection events that are impactful or numerous, or disk I/O happening concurrently with initialization, which further blocks the initialization process. Garbage collection is especially a consideration with the Dalvik runtime; the Android Runtime (ART) performs garbage collection concurrently, minimizing that operation's impact.
Diagnose the problem
You can use method tracing or inline tracing to try to diagnose the problem.
Method tracing
Running the CPU Profiler reveals that the
callApplicationOnCreate()
method eventually calls your com.example.customApplication.onCreate
method. If
the tool shows that these methods are taking a long time to finish executing,
explore further to see what work is occurring there.
Inline tracing
Use inline tracing to investigate likely culprits, including the following:
- Your app's initial
onCreate()
function. - Any global singleton objects your app initializes.
- Any disk I/O, deserialization, or tight loops that might be occurring during the bottleneck.
Solutions to the problem
Whether the problem lies with unnecessary initializations or with disk I/O, the solution is lazy initialization. In other words, only initialize objects that are immediately needed. Instead of creating global static objects, move to a singleton pattern where the app initializes objects only the first time it needs them.
Also, consider using a dependency injection framework like Hilt that creates objects and dependencies when they are injected for the first time.
If your app uses content providers to initialize app components at startup, consider using the App Startup library instead.
Heavy activity initialization
Activity creation often entails a lot of high-overhead work. Often, there are opportunities to optimize this work to achieve performance improvements. Such common issues include the following:
- Inflating large or complex layouts.
- Blocking screen drawing on disk, or network I/O.
- Loading and decoding bitmaps.
- Rasterizing
VectorDrawable
objects. - Initialization of other subsystems of the activity.
Diagnose the problem
In this case, as well, both method tracing and inline tracing can be useful.
Method tracing
When using the CPU Profiler, pay attention to your app's
Application
subclass constructors and
com.example.customApplication.onCreate()
methods.
If the tool shows that these methods are taking a long time to finish executing, explore further to see what work is occurring there.
Inline tracing
Use inline tracing to investigate likely culprits, including the following:
- Your app's initial
onCreate()
function. - Any global singleton objects it initializes.
- Any disk I/O, deserialization, or tight loops that might be occurring during the bottleneck.
Solutions to the problem
There are many potential bottlenecks, but two common problems and remedies are as follows:
- The larger your view hierarchy, the more time the app takes to inflate it.
Two steps you can take to address this issue are the following:
- Flatten your view hierarchy by reducing redundant or nested layouts.
- Don't inflate parts of the UI that don't need to be visible during
launch. Instead, use a
ViewStub
object as a placeholder for sub-hierarchies that the app can inflate at a more appropriate time.
- Having all of your resource initialization on the main thread can also slow
down startup. You can address this issue as follows:
- Move all resource initialization so that the app can perform it lazily on a different thread.
- Let the app load and display your views, and then later update visual properties that are dependent on bitmaps and other resources.
Custom splash screens
You might see extra time added during startup if you previously used one of the following methods to implement a custom splash screen in Android 11 (API level 30) or earlier:
- Using the
windowDisablePreview
theme attribute to turn off the initial blank screen drawn by the system during launch. - Using a dedicated
Activity
.
Starting with Android 12, migrating to the
SplashScreen
API is required. This
API enables a faster startup time and lets you tweak your splash screen in the
following ways:
- Set a theme to change the splash screen's appearance.
- Control how long the splash screen is displayed with
windowSplashScreenAnimationDuration
. - Customize the splash screen animation, and gracefully handle the animation for dismissing the splash screen.
Furthermore, the compat library backports the SplashScreen
API to enable
backward-compatibility and to create a consistent look and feel for splash
screen display across all Android versions.
See the Splash screen migration guide for details.
Recommended for you
- Note: link text is displayed when JavaScript is off
- Slow rendering
- Capture Macrobenchmark metrics
- Create Baseline Profiles {:#creating-profile-rules}