Warm Start is an Android app launch scenario where the app process already exists in memory (e.g., after being minimized), but the Activity was destroyed by the system to save resources. Application.onCreate has already been executed, classes are loaded, but the UI is created anew. According to Google, 2024, Warm Start takes 200–800 ms and accounts for about 40% of all launches on devices with 4 GB RAM.
Key Takeaways
Warm Start is a state between Cold Start and Hot Start: the app process exists in memory (sometimes in the Linux background cache), but the Activity is not active and will be created anew. When Android runs low on RAM, it may evict the Activity from the stack, leaving the process alive. When the user returns to the app, a Warm Start occurs: a new Activity instance is created, lifecycle methods onCreate → onStart → onResume execute, but Application.onCreate and class loading are skipped.
Android decides to evict the Activity based on process priority (importance rank). An Activity in the background (level PROCESS_STATE_IMPORTANT_FOREGROUND or PROCESS_STATE_TOP_SLEEPING) may be destroyed 5–30 minutes after the app is minimized, depending on available RAM. On devices with 3 GB RAM, the Activity may be evicted within 10 minutes; on devices with 8 GB RAM, after several hours. Importantly, during Warm Start onSaveInstanceState is called before the Activity is destroyed, and the developer can save the UI state.
The user does not see the difference between Warm and Cold Start — they simply tap the app icon and wait. However, during Warm Start, a blank white screen may appear if the app has not set a custom startup window theme. Google recommends setting a custom theme in the manifest (Theme.AppCompat.Light or Theme.Material3.DayNight) for the startup Activity to avoid white/black screen flickering during Warm Start. On Android 12+, the SplashScreen API also hides this effect.
Understanding the difference between the three launch types is essential for choosing the right profiling and optimization strategy. Each type has its own duration, bottlenecks, and measurement tools.
| Criterion | Cold Start | Warm Start | Hot Start |
|---|---|---|---|
| Process | Created from scratch | Exists in memory | Exists in memory |
| Application.onCreate | Executed | Not executed | Not executed |
| Activity | Created from scratch | Created from scratch | Restored from stack |
| Time | 1–5 seconds | 200–800 ms | < 200 ms |
| Activity onCreate | Full | Full (with restore) | Skipped |
In practice, Warm Start accounts for 30% to 60% of all app launches, depending on user habits and device RAM. Users who keep many apps open (multitaskers) encounter Warm Start more often. For social networks and messengers, Warm Start is the most common scenario since the app is always in the background. For banking apps, on the other hand, Cold Start prevails (forced process cleanup for security reasons).
Warm Start consists of three phases, each of which can be measured and optimized. Unlike Cold Start, there is no fork phase or class loading, but there is a state restoration phase that can be expensive.
The system checks if the app has a startup window theme. If the theme is not set, a white (or black, depending on the system) screen is displayed. If the theme is set, the theme background is shown. This phase takes 10–30 ms, but it is visually noticeable if the theme does not match the app’s actual UI. Use Theme.Material3.DayNight with a custom windowBackground whose color matches the first screen’s background — this creates an instant loading effect.
The system calls onCreate passing the Bundle savedInstanceState that was saved in onSaveInstanceState before the Activity was destroyed. If the app properly saved the state (field text, scroll position, ViewModel data), restoration happens quickly. If not, the Activity starts from scratch and the user sees a loader while data loads. Key point: ViewModel objects survive Warm Start only if the process was not destroyed — during Warm Start, the ViewModel stays in memory.
After onCreate, onStart → onResume execute, and the system triggers the first draw. TTFD (Time To First Draw) for Warm Start should be under 300 ms on a mid-range device. If the first screen contains a complex RecyclerView with heavy Views or loads images from the network, TTFD may exceed the threshold. Use Placeholder and Shimmer for smooth content loading after the first frame.
Measuring Warm Start is more complex than Cold Start because you need to simulate the state where the process is alive but the Activity is destroyed. The standard ADB command with the -S flag does not work — it kills the process. Use different approaches for Warm Start.
First, launch the app via adb shell monkey or tap the icon, then minimize it (adb shell input keyevent 3 keyevent HOME). Wait 5–10 seconds so the system can evict the Activity, then run adb shell am start -W (without -S). The command will return a shorter startup time than Cold Start. For reproducibility, use a script: launch → wait → home → wait → launch.
# Simulating Warm Start via ADB
$ adb shell am start -W \
com.example.app/.MainActivity
# Output (Warm Start):
# ThisTime: 412 ms
# TotalTime: 412 ms
# WaitTime: 423 ms
The androidx.benchmark.macro library supports Warm Start measurement. In the test, set startupMode = StartupMode.WARM — the library will launch the app, minimize it, wait (configurable delay), and then measure the relaunch. Macrobenchmark runs 10–20 iterations and calculates percentiles. In CI/CD, you can set a threshold: if P50 Warm Start exceeds 600 ms, the test fails. This allows tracking regressions with every commit.
Firebase automatically distinguishes Cold and Warm Start based on the time since the last app close. If the app was opened within the last 30 minutes, Firebase classifies the launch as Warm. In the Firebase console, you will see separate charts for each startup type, allowing you to evaluate optimization effectiveness. For example, after implementing state preservation in ViewModel, you may see a 30% reduction in Warm Start time.
Warm Start optimization focuses on two areas: speeding up Activity.onCreate and proper state restoration. Since Application.onCreate and class loading have already been completed, the main bottleneck is the first screen’s UI code.
If the saved state (savedInstanceState) contains data that needs deserialization (Bitmap, String, JSON), do this on a background thread. Instead of directly reading from Bundle in onCreate, launch a coroutine and show a shimmer screen. In practice, Bundle deserialization on a mid-range device takes 20–100 ms — it seems small, but for Warm Start, this is 10–50% of the total time. Use the Jetpack Saved State Module, which automatically saves and restores ViewModel state in the Bundle or database.
XML layout inflation is one of the most expensive stages of Warm Start. If the first screen uses a complex CoordinatorLayout with AppBar, CollapsingToolbar, NestedScrollView plus three RecyclerViews, inflation time can reach 300 ms. Solutions: use ConstraintLayout for a flat hierarchy, apply ViewStub for sections not visible at startup (bottom sheet, dialog), enable asynchronous inflation for heavy fragments via AsyncLayoutInflater. In Jetpack Compose, inflation is not needed, but Compose tree compilation during Warm Start may take a similar amount of time.
During Warm Start, data the app loaded in the previous session may already be in cache: Room database, SharedPreferences, in-memory cache in ViewModel. If your first screen displays a list from the server, check the cache at startup and update data in the background. Use the cache-then-network strategy: first display cached data (instantly), then update from the server (asynchronously). This reduces the perceived Warm Start time to 100–200 ms.
// ViewModel with caching for Warm Start
class FeedViewModel : ViewModel() {
private val cache = MutableStateFlow<List<Item>>(emptyList())
init {
// Cache first, then network
viewModelScope.launch {
cache.emit(db.getItems()) // Warm Start: data already in DB
cache.emit(api.fetchItems()) // Background update
}
}
}
Proper state preservation is the key factor that distinguishes a good Warm Start from a bad one. The user expects to return to the app and see exactly what they left — including scroll position, text in fields, and selected tabs.
The system calls onSaveInstanceState when the Activity is being destroyed, but BEFORE the process may be killed. Only simple data types (String, Int, Parcelable, Serializable) are saved in the Bundle. For complex data, use SavedStateHandle in ViewModel — it automatically saves and restores fields during Warm Start. Unlike onSaveInstanceState, SavedStateHandle works even if the process survives Warm Start (ViewModel is not destroyed). Example: for text in EditText, use SavedStateHandle.getLiveData(“text”) — the text will be automatically saved and restored.
If the process was not killed during Warm Start, the ViewModel stays in memory and onCleared is not called. This means all data loaded in the previous session is instantly available. However, if the process was killed (device in deep sleep for more than 30 minutes), the ViewModel is destroyed and created anew with SavedStateHandle. For correct ViewModel behavior during Warm Start, use SavedStateHandle with fields that need to be restored in any scenario. Difference: ViewModel with @HiltViewModel supports SavedStateHandle automatically.
| Mechanism | Process Alive | Process Killed |
|---|---|---|
| ViewModel | Data in memory | Destroyed, created anew |
| SavedStateHandle | Data in memory | Restored from Bundle |
| onSaveInstanceState | Called on Activity eviction | Not called |
| Room DB | Cache available | Cache available (disk) |
One of the most common Warm Start issues — losing the scroll position. The user scrolled to the 50th item, minimized the app, returned — and sees the beginning of the list. Solution: save layoutManager.onSaveInstanceState (saves the position and offset of the first visible item) and restore it in onRestoreInstanceState. You can also save the last visible position in SharedPreferences with a date/time key to quickly restore the position during Warm Start.
// Saving RecyclerView scroll position
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putParcelable(
"rv_state", binding.recyclerView
.layoutManager?.onSaveInstanceState()
)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
savedInstanceState?.getParcelable<Parcelable>("rv_state")
?.let { binding.recyclerView.layoutManager?.onRestoreInstanceState(it) }
}
Two practical examples of Warm Start optimization: using SavedStateHandle in ViewModel and asynchronous restoration of complex data after startup.
SavedStateHandle automatically saves fields to the Bundle and restores them during Warm Start. The user profile field (String, JSON) will be restored without unnecessary server requests. If the process was killed, SavedStateHandle loads the last saved state from the Bundle.
class ProfileViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val profile: StateFlow<Profile?>
get() = savedStateHandle
.getStateFlow("profile", null)
fun loadProfile(id: String) {
viewModelScope.launch {
savedStateHandle["profile"] =
api.getProfile(id)
}
}
}
// Warm Start: profile is not null, UI without loader
// After loading: profile updates in SavedStateHandle
If the first screen contains a complex layout (map, gradient, multiple lists), use AsyncLayoutInflater to inflate heavy elements in the background. While the layout is being inflated, show a placeholder with a shimmer effect. This is especially important for Warm Start, where every millisecond counts. AsyncLayoutInflater runs on a background thread and passes the ready View to a callback on the main thread.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Placeholder layout for instant rendering
setContentView(R.layout.placeholder_shimmer)
// Asynchronous loading of heavy layout
AsyncLayoutInflater(this).inflate(
R.layout.activity_main_complex,
findViewById(R.id.container)
) { view, resId, parent ->
parent?.removeAllViews()
parent?.addView(view)
}
}
}
Frequently Asked Questions
Yes, if at the moment of Warm Start the system decides to kill the app process (e.g., to free memory for another app), the launch becomes a Cold Start from scratch. This happens on devices with 2–3 GB RAM when multiple apps are running simultaneously. In fact, Warm Start is only guaranteed for 10–20 minutes after minimizing on mid-range devices.
Yes, if the process was not killed, the ViewModel stays in memory and onCleared is not called. This is a key advantage of Warm Start: all data loaded via network requests, the cache in ViewModel — all available instantly. If the process was killed, the ViewModel is created anew through ViewModelProvider.Factory or @HiltViewModel, and SavedStateHandle restores the saved fields.
Theoretically, Warm Start is always faster than Cold Start, but in practice there are scenarios where the difference is minimal: if Application.onCreate was lightweight (50 ms) and Activity.onCreate is heavy (800 ms), then Warm Start (800 ms) is almost equal to Cold Start (850 ms). In this case, you should optimize not Application, but Activity.onCreate — it becomes the bottleneck for Warm Start.
The SplashScreen API on Android 12+ shows a system splash (icon on a colored background) immediately at startup — for both Cold and Warm Start. For Warm Start, the splash is displayed for only 100–300 ms, after which it is replaced by the app’s UI. SplashScreen does not speed up the launch itself, but masks the Activity creation time, improving perception.
Yes, because Warm Start occurs 2–3 times more often than Cold Start. If Cold Start takes 1.2 seconds and Warm Start takes 600 ms, then 40% of launches (Warm) still take 0.6 seconds, which is noticeable. Optimizing Warm Start down to 200–300 ms gives the user a feeling of instant return. On devices with 6+ GB RAM, Warm Start can account for up to 80% of all launches, making its optimization a priority.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also