Warm Start is een opstartscenario van een Android-app waarbij het proces van de app al in het geheugen bestaat (bijvoorbeeld na minimaliseren), maar de Activity door het systeem is vernietigd om bronnen te besparen. Application.onCreate is al uitgevoerd, klassen zijn geladen, maar de UI wordt opnieuw aangemaakt. Volgens Google, 2024 duurt Warm Start 200 tot 800 ms en vormt ongeveer 40% van alle starts op apparaten met 4 GB RAM.
Belangrijkste punten
Warm Start (warme start) is een toestand tussen Cold Start en Hot Start: het proces van de app bestaat in het geheugen (soms in de Linux-achtergrondcache), maar de Activity is niet actief en wordt opnieuw aangemaakt. Het Android-systeem kan bij gebrek aan RAM de Activity uit de stack verwijderen terwijl het proces in leven blijft. Wanneer de gebruiker terugkeert naar de app, begint Warm Start: een nieuw exemplaar van Activity wordt aangemaakt, de lifecycle-methoden onCreate → onStart → onResume worden uitgevoerd, maar Application.onCreate en het laden van klassen worden overgeslagen.
Het Android-systeem beslist over het verwijderen van Activity op basis van de procesprioriteit (importance rank). Activity op de achtergrond (niveau PROCESS_STATE_IMPORTANT_FOREGROUND of PROCESS_STATE_TOP_SLEEPING) kan 5–30 minuten na het minimaliseren van de app worden vernietigd, afhankelijk van het beschikbare RAM. Op apparaten met 3 GB RAM kan Activity na 10 minuten worden verwijderd, op apparaten met 8 GB — na enkele uren. Belangrijk: bij Warm Start wordt onSaveInstanceState aangeroepen vóór vernietiging van Activity en kan de ontwikkelaar de UI-status opslaan.
De gebruiker ziet geen verschil tussen Warm en Cold Start — hij klikt gewoon op het app-pictogram en wacht. Bij Warm Start kan echter een wit scherm (blank window) verschijnen als de app geen eigen thema voor het startvenster heeft ingesteld. Google raadt aan een aangepast thema in het manifest in te stellen (Theme.AppCompat.Light of Theme.Material3.DayNight) voor de start-Activity om flikkeren van wit/zwart scherm bij Warm Start te voorkomen. Op Android 12+ verbergt SplashScreen API dit effect ook.
Inzicht in het verschil tussen de drie typen starts is nodig voor het kiezen van de juiste profilering- en optimalisatiestrategie. Elk type heeft zijn eigen duur, knelpunten en meetinstrumenten.
| Criterium | Cold Start | Warm Start | Hot Start |
|---|---|---|---|
| Proces | Opnieuw aangemaakt | Bestaat in geheugen | Bestaat in geheugen |
| Application.onCreate | Wordt uitgevoerd | Wordt niet uitgevoerd | Wordt niet uitgevoerd |
| Activity | Vanaf nul aangemaakt | Vanaf nul aangemaakt | Hersteld uit stack |
| Tijd | 1–5 seconden | 200–800 ms | < 200 ms |
| onCreate Activity | Volledig | Volledig (met restore) | Overgeslagen |
In de praktijk vormt Warm Start 30% tot 60% van alle app-starts, afhankelijk van gebruikersgewoonten en de hoeveelheid RAM van het apparaat. Gebruikers die veel apps open houden (multitaskers) krijgen vaker met Warm Start te maken. Voor sociale netwerken en messengers is Warm Start het meest voorkomende scenario omdat de app altijd op de achtergrond draait. Voor bankapps daarentegen overheerst Cold Start (gedwongen procesopschoning om veiligheidsredenen).
Warm Start bestaat uit drie fasen, die elk kunnen worden gemeten en geoptimaliseerd. In tegenstelling tot Cold Start is er hier geen fork-fase en het laden van klassen, maar er is een herstelfase (restore) die kostbaar kan zijn.
Het systeem controleert of de app een thema heeft voor het startvenster. Als er geen thema is ingesteld, wordt een wit (of zwart, afhankelijk van het systeem) scherm weergegeven. Als er een thema is ingesteld, wordt de achtergrond uit het thema weergegeven. Deze fase duurt 10–30 ms, maar is visueel voelbaar als het thema niet overeenkomt met de werkelijke UI van de app. Gebruik Theme.Material3.DayNight met een aangepaste windowBackground waarvan de kleur overeenkomt met de achtergrond van het eerste scherm — dit creëert een effect van onmiddellijk laden.
Het systeem roept onCreate aan met Bundle savedInstanceState die was opgeslagen in onSaveInstanceState vóór vernietiging van Activity. Als de app de status correct heeft opgeslagen (veldtekst, scrollpositie, ViewModel-gegevens), verloopt het herstel snel. Zo niet — dan begint Activity met een lege pagina en ziet de gebruiker een loader tot de gegevens zijn geladen. Belangrijk punt: ViewModel-objecten overleven Warm Start alleen als het proces niet is vernietigd — bij Warm Start blijft ViewModel in het geheugen.
Na onCreate worden onStart → onResume uitgevoerd en roept het systeem de eerste weergave aan. TTFD (Time To First Draw) voor Warm Start moet minder dan 300 ms zijn op een gemiddeld apparaat. Als het eerste scherm een complexe RecyclerView met zware Views bevat of afbeeldingen via het netwerk laadt, kan TTFD de drempel overschrijden. Gebruik Placeholder en Shimmer voor soepel laden van content na het eerste frame.
Het meten van Warm Start is complexer dan Cold Start omdat u de toestand «proces leeft, Activity vernietigd» moet simuleren. Het standaard ADB-commando met de vlag -S is niet geschikt — het doodt het proces. Gebruik voor Warm Start andere benaderingen.
Start eerst de app via adb shell monkey of tik op het pictogram, minimaliseer deze vervolgens (adb shell input keyevent 3 keyevent HOME). Wacht 5–10 seconden zodat het systeem de Activity kan verwijderen en voer adb shell am start -W (zonder -S) uit. Het commando geeft de starttijd terug die korter zal zijn dan Cold Start. Gebruik voor reproduceerbaarheid een script: start → wacht → home → wacht → start.
# Simulatie van Warm Start via ADB
$ adb shell am start -W \
com.example.app/.MainActivity
# Uitvoer (Warm Start):
# ThisTime: 412 ms
# TotalTime: 412 ms
# WaitTime: 423 ms
De bibliotheek androidx.benchmark.macro ondersteunt het meten van Warm Start. Stel hiervoor in de test startupMode = StartupMode.WARM in — de bibliotheek start de app, minimaliseert deze, wacht (configureerbare vertraging) en meet vervolgens de herstart. Macrobenchmark voert 10–20 runs uit en berekent percentielen. In CI/CD kunt u een drempel instellen: als P50 Warm Start 600 ms overschrijdt — faalt de test. Dit maakt het mogelijk regressies bij elke commit te volgen.
Firebase onderscheidt automatisch Cold en Warm Start op basis van de tijd sinds de vorige sluiting van de app. Als de app in de laatste 30 minuten is geopend, classificeert Firebase de start als Warm. In de Firebase-console ziet u aparte grafieken voor elk starttype, waarmee u de effectiviteit van optimalisaties kunt evalueren. Na implementatie van statusopslag in ViewModel kunt u bijvoorbeeld een verlaging van Warm Start met 30% zien.
Optimalisatie van Warm Start richt zich op twee gebieden: het versnellen van Activity.onCreate en het correct herstellen van de status. Omdat Application.onCreate en het laden van klassen al zijn uitgevoerd, is het belangrijkste knelpunt de UI-code van het eerste scherm.
Als de opgeslagen status (savedInstanceState) gegevens bevat die gedeserialiseerd moeten worden (Bitmap, String, JSON), doe dit dan op de achtergrond. In plaats van direct uit Bundle te lezen in onCreate, start u een coroutine en toont u een shimmer-scherm. In de praktijk duurt deserialisatie van Bundle op een gemiddeld apparaat 20–100 ms — lijkt weinig, maar voor Warm Start is dit 10–50% van de totale tijd. Gebruik de Saved State Module van de Jetpack-bibliotheek die automatisch de ViewModel-status opslaat en herstelt in Bundle of database.
Het opblazen van XML-layout (layout inflation) is een van de duurste stappen van Warm Start. Als het eerste scherm een complexe CoordinatorLayout gebruikt met AppBar, CollapsingToolbar, NestedScrollView plus drie RecyclerViews, kan de inflatietijd 300 ms bereiken. Oplossingen: gebruik ConstraintLayout voor een platte hiërarchie, pas ViewStub toe voor bij start onzichtbare secties (bottom sheet, dialog), schakel asynchroon opblazen voor zware fragmenten in via AsyncLayoutInflater. In Jetpack Compose is inflation niet nodig, maar het compileren van de Compose-boom bij Warm Start kan vergelijkbare tijd kosten.
Bij Warm Start kunnen gegevens die de app in de vorige sessie heeft geladen al in de cache zitten: Room-database, SharedPreferences, in-memory cache in ViewModel. Als uw eerste scherm een lijst van de server toont, controleer dan de cache bij start en werk de gegevens op de achtergrond bij. Gebruik de strategie cache-then-network: toon eerst de gecachte gegevens (onmiddellijk), werk vervolgens bij vanaf de server (asynchroon). Dit verkort de waargenomen tijd van Warm Start tot 100–200 ms.
// ViewModel met caching voor Warm Start
class FeedViewModel : ViewModel() {
private val cache = MutableStateFlow<List<Item>>(emptyList())
init {
// Eerst cache, dan netwerk
viewModelScope.launch {
cache.emit(db.getItems()) // Warm Start: gegevens al in database
cache.emit(api.fetchItems()) // Achtergrondupdate
}
}
}
Correcte statusopslag is de sleutelfactor die een goede Warm Start onderscheidt van een slechte. De gebruiker verwacht terug te keren naar de app en hetzelfde te zien als wat hij heeft achtergelaten — inclusief scrollpositie, tekst in velden, geselecteerde tabbladen.
Het systeem roept onSaveInstanceState aan bij vernietiging van Activity, maar VOORDAT het proces kan worden gedood. In Bundle worden alleen eenvoudige gegevens opgeslagen (String, Int, Parcelable, Serializable). Gebruik voor complexe gegevens SavedStateHandle in ViewModel — het slaat automatisch velden op en herstelt ze bij Warm Start. In tegenstelling tot onSaveInstanceState werkt SavedStateHandle zelfs als het proces Warm Start heeft overleefd (ViewModel wordt niet vernietigd). Voorbeeld: gebruik voor tekst in EditText SavedStateHandle.getLiveData(«text») — de tekst wordt automatisch opgeslagen en hersteld.
Als bij Warm Start het proces niet is gedood, blijft ViewModel in het geheugen en wordt onCleared niet aangeroepen. Dit betekent dat alle in de vorige sessie geladen gegevens onmiddellijk beschikbaar zijn. Maar als het proces is gedood (apparaat in deep sleep langer dan 30 minuten), wordt ViewModel vernietigd en opnieuw aangemaakt met SavedStateHandle. Voor correct werken van ViewModel bij Warm Start gebruikt u SavedStateHandle met velden die in elk scenario moeten worden hersteld. Verschil: ViewModel met @HiltViewModel ondersteunt SavedStateHandle automatisch.
| Mechanisme | Proces leeft | Proces gedood |
|---|---|---|
| ViewModel | Gegevens in geheugen | Vernietigd, opnieuw aangemaakt |
| SavedStateHandle | Gegevens in geheugen | Hersteld uit Bundle |
| onSaveInstanceState | Aangeroepen bij verwijdering Activity | Niet aangeroepen |
| Room DB | Cache beschikbaar | Cache beschikbaar (schijf) |
Een van de meest voorkomende problemen bij Warm Start — verlies van scrollpositie. De gebruiker heeft door de feed naar het 50e element gescrolld, de app geminimaliseerd, keerde terug — en ziet het begin van de lijst. Oplossing: sla layoutManager.onSaveInstanceState op (bewaart positie en offset van het eerste zichtbare element) en herstel het in onRestoreInstanceState. U kunt ook de laatste zichtbare positie opslaan in SharedPreferences met een datum/tijd-sleutel om bij Warm Start snel de positie te herstellen.
// Scrollpositie RecyclerView behouden
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) }
}
Twee praktische voorbeelden van Warm Start-optimalisatie: gebruik van SavedStateHandle in ViewModel en asynchroon herstel van complexe gegevens na de start.
SavedStateHandle slaat automatisch velden op in Bundle en herstelt ze bij Warm Start. Het gebruikersprofielveld (String, JSON) wordt hersteld zonder extra serververzoeken. Als het proces is gedood, laadt SavedStateHandle de laatst opgeslagen status uit 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 niet null, UI zonder loader
// Na laden: profile wordt bijgewerkt in SavedStateHandle
Als het eerste scherm een complexe layout bevat (kaart, verloop, meerdere lijsten), gebruik dan AsyncLayoutInflater voor het opblazen van zware elementen op de achtergrond. Terwijl de layout wordt opgeblazen, toon een placeholder met shimmer-effect. Dit is vooral belangrijk voor Warm Start, waar elke milliseconde telt. AsyncLayoutInflater werkt op de achtergrond en levert de kant-en-klare View via callback aan de hoofdthread.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Placeholder-layout voor onmiddellijke weergave
setContentView(R.layout.placeholder_shimmer)
// Asynchroon laden van zware layout
AsyncLayoutInflater(this).inflate(
R.layout.activity_main_complex,
findViewById(R.id.container)
) { view, resId, parent ->
parent?.removeAllViews()
parent?.addView(view)
}
}
}
Veelgestelde vragen
Ja, als het systeem op het moment van Warm Start besluit het app-proces te doden (bijvoorbeeld om geheugen vrij te maken voor een andere app), wordt de start een Cold Start vanaf nul. Dit gebeurt op apparaten met 2–3 GB RAM bij gelijktijdig gebruik van meerdere apps. In de praktijk is Warm Start slechts 10–20 minuten na minimaliseren gegarandeerd op middenklasse apparaten.
Ja, als het proces niet is gedood, blijft ViewModel in het geheugen en wordt onCleared niet aangeroepen. Dit is het belangrijkste voordeel van Warm Start: alle geladen gegevens, netwerkverzoeken, cache in ViewModel — onmiddellijk beschikbaar. Als het proces is gedood, wordt ViewModel opnieuw aangemaakt via ViewModelProvider.Factory of @HiltViewModel en herstelt SavedStateHandle de opgeslagen velden.
Theoretisch is Warm Start altijd sneller dan Cold Start, maar in de praktijk zijn er scenario's waarin het verschil minimaal is: als Application.onCreate licht (50 ms) en Activity.onCreate zwaar (800 ms) is, dan is Warm Start (800 ms) bijna gelijk aan Cold Start (850 ms). In dit geval moet niet Application, maar Activity.onCreate worden geoptimaliseerd — dat wordt het knelpunt voor Warm Start.
SplashScreen API op Android 12+ toont een systeemsplash (pictogram op gekleurde achtergrond) onmiddellijk bij start — zowel voor Cold als Warm Start. Voor Warm Start wordt de splash slechts 100–300 ms weergegeven, waarna deze wordt vervangen door de app-UI. SplashScreen versnelt de start zelf niet, maar maskeert de tijd van Activity-creatie en verbetert de perceptie.
Ja, omdat Warm Start 2–3 keer vaker voorkomt dan Cold Start. Als Cold Start 1,2 seconden duurt en Warm Start 600 ms, dan duren 40% van de starts (Warm) nog steeds 0,6 seconden, wat voelbaar is. Optimalisatie van Warm Start tot 200–300 ms geeft de gebruiker het gevoel van onmiddellijke terugkeer. Op apparaten met 6+ GB RAM kan Warm Start tot 80% van alle starts uitmaken en wordt optimalisatie een prioriteit.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook