Warm Start är ett startscenario för en Android-app där appens process redan finns i minnet (till exempel efter minimering), men Activity har förstörts av systemet för att spara resurser. Application.onCreate har redan körts, klasser har laddats, men UI skapas på nytt. Enligt Google, 2024 tar Warm Start 200 till 800 ms och utgör cirka 40% av alla starter på enheter med 4 GB RAM.
Huvudpunkter
Warm Start (varmstart) är ett tillstånd mellan Cold Start och Hot Start: appens process finns i minnet (ibland i Linux bakgrundscache), men Activity är inte aktiv och kommer att skapas på nytt. Android-systemet vid RAM-brist kan ta bort Activity från stacken och låta processen vara vid liv. När användaren återvänder till appen börjar Warm Start: en ny instans av Activity skapas, livscykelmetoderna onCreate → onStart → onResume körs, men Application.onCreate och klassladdning hoppas över.
Android-systemet beslutar om borttagning av Activity baserat på processprioritet (importance rank). En Activity i bakgrunden (nivå PROCESS_STATE_IMPORTANT_FOREGROUND eller PROCESS_STATE_TOP_SLEEPING) kan förstöras 5–30 minuter efter app-minimering, beroende på tillgängligt RAM. På enheter med 3 GB RAM kan Activity tas bort efter 10 minuter, på enheter med 8 GB — efter flera timmar. Viktigt: vid Warm Start anropas onSaveInstanceState före förstörelse av Activity och utvecklaren kan spara UI-tillståndet.
Användaren ser ingen skillnad mellan Warm och Cold Start — han trycker bara på appikonen och väntar. Men vid Warm Start kan en vit skärm (blank window) visas om appen inte har ställt in ett eget tema för startfönstret. Google rekommenderar att ställa in ett anpassat tema i manifestet (Theme.AppCompat.Light eller Theme.Material3.DayNight) för start-Activity för att undvika flimmer av vit/svart skärm vid Warm Start. På Android 12+ döljer SplashScreen API också denna effekt.
Att förstå skillnaden mellan de tre starttyperna är nödvändigt för att välja rätt profilerings- och optimeringsstrategi. Varje typ har sin egen varaktighet, sina egna flaskhalsar och sina egna mätverktyg.
| Kriterium | Cold Start | Warm Start | Hot Start |
|---|---|---|---|
| Process | Skapas på nytt | Finns i minnet | Finns i minnet |
| Application.onCreate | Körs | Körs inte | Körs inte |
| Activity | Skapas från början | Skapas från början | Återställs från stacken |
| Tid | 1–5 sekunder | 200–800 ms | < 200 ms |
| onCreate Activity | Fullständig | Fullständig (med restore) | Hoppas över |
I praktiken utgör Warm Start 30% till 60% av alla appstarter, beroende på användarens vanor och enhetens RAM-mängd. Användare som håller många appar öppna (multitasker) stöter oftare på Warm Start. För sociala nätverk och meddelandetjänster är Warm Start det vanligaste scenariot eftersom appen alltid är i bakgrunden. För bankappar dominerar däremot Cold Start (tvångsrengöring av processen av säkerhetsskäl).
Warm Start består av tre faser, som var och en kan mätas och optimeras. Till skillnad från Cold Start finns det ingen fork-fas och klassladdning, men det finns en återställningsfas (restore) som kan vara kostsam.
Systemet kontrollerar om appen har ett tema för startfönstret. Om inget tema har ställts in visas en vit (eller svart, beroende på system) skärm. Om ett tema har ställts in visas bakgrunden från temat. Denna fas tar 10–30 ms, men är visuellt märkbar om temat inte matchar appens verkliga UI. Använd Theme.Material3.DayNight med anpassad windowBackground vars färg matchar den första skärmens bakgrund — detta skapar en effekt av omedelbar laddning.
Systemet anropar onCreate med Bundle savedInstanceState som sparades i onSaveInstanceState före förstörelse av Activity. Om appen sparade tillståndet korrekt (fälttext, scrollposition, ViewModel-data) sker återställningen snabbt. Om inte — börjar Activity från en tom sida och användaren ser en loader tills data har laddats. Nyckelpunkt: ViewModel-objekt överlever Warm Start endast om processen inte förstördes — vid Warm Start förblir ViewModel i minnet.
Efter onCreate körs onStart → onResume och systemet anropar första renderingen. TTFD (Time To First Draw) för Warm Start bör vara mindre än 300 ms på en medelstor enhet. Om den första skärmen innehåller en komplex RecyclerView med tunga Views eller laddar bilder via nätverket kan TTFD överskrida tröskeln. Använd Placeholder och Shimmer för smidig laddning av innehåll efter den första bildrutan.
Att mäta Warm Start är mer komplicerat än Cold Start eftersom du måste simulera tillståndet «processen lever, Activity förstörd». Standardkommandot ADB med flaggan -S är inte lämpligt — det dödar processen. För Warm Start använd andra metoder.
Starta först appen via adb shell monkey eller tryck på ikonen, minimera den sedan (adb shell input keyevent 3 keyevent HOME). Vänta 5–10 sekunder så att systemet kan ta bort Activity och kör adb shell am start -W (utan -S). Kommandot returnerar starttiden som blir kortare än Cold Start. För reproducerbarhet använd ett skript: starta → vänta → home → vänta → starta.
# Simulering av Warm Start via ADB
$ adb shell am start -W \
com.example.app/.MainActivity
# Utdata (Warm Start):
# ThisTime: 412 ms
# TotalTime: 412 ms
# WaitTime: 423 ms
Biblioteket androidx.benchmark.macro stöder mätning av Warm Start. För detta i testet ställ in startupMode = StartupMode.WARM — biblioteket startar appen, minimerar den, väntar (konfigurerbar fördröjning) och mäter sedan omstarten. Macrobenchmark gör 10–20 körningar och beräknar percentiler. I CI/CD kan du ställa in en tröskel: om P50 Warm Start överstiger 600 ms — testet misslyckas. Detta gör det möjligt att spåra regressioner vid varje commit.
Firebase skiljer automatiskt mellan Cold och Warm Start baserat på tiden sedan appen senast stängdes. Om appen har öppnats under de senaste 30 minuterna klassificerar Firebase starten som Warm. I Firebase-konsolen ser du separata diagram för varje starttyp, vilket gör att du kan utvärdera effektiviteten av optimeringar. Efter implementering av tillståndslagring i ViewModel kan du till exempel se en minskning av Warm Start med upp till 30%.
Optimering av Warm Start fokuserar på två riktningar: att påskynda Activity.onCreate och korrekt återställning av tillstånd. Eftersom Application.onCreate och klassladdning redan har utförts är den främsta flaskhalsen UI-koden på den första skärmen.
Om det sparade tillståndet (savedInstanceState) innehåller data som måste deserialiseras (Bitmap, String, JSON), gör detta i en bakgrundstråd. Istället för att läsa direkt från Bundle i onCreate, starta en coroutine och visa en shimmer-skärm. I praktiken tar deserialisering av Bundle på en medelstor enhet 20–100 ms — verkar lite, men för Warm Start är detta 10–50% av den totala tiden. Använd Saved State Module från Jetpack-biblioteket som automatiskt sparar och återställer ViewModel-tillståndet i Bundle eller databas.
Expandering av XML-layout (layout inflation) är ett av de dyraste stegen i Warm Start. Om den första skärmen använder en komplex CoordinatorLayout med AppBar, CollapsingToolbar, NestedScrollView och tre RecyclerView kan inflationstiden nå 300 ms. Lösningar: använd ConstraintLayout för platt hierarki, tillämpa ViewStub för sektioner som är osynliga vid start (bottom sheet, dialog), aktivera asynkron expandering för tunga fragment via AsyncLayoutInflater. I Jetpack Compose behövs ingen inflation, men kompilering av Compose-trädet vid Warm Start kan ta liknande tid.
Vid Warm Start kan data som appen laddade i föregående session redan finnas i cachen: Room-databas, SharedPreferences, in-memory cache i ViewModel. Om din första skärm visar en lista från servern, kontrollera cachen vid start och uppdatera data i bakgrunden. Använd strategin cache-then-network: visa först cachad data (omedelbart), uppdatera sedan från servern (asynkront). Detta minskar den upplevda tiden för Warm Start till 100–200 ms.
// ViewModel med cachning för Warm Start
class FeedViewModel : ViewModel() {
private val cache = MutableStateFlow<List<Item>>(emptyList())
init {
// Cache först, sedan nätverk
viewModelScope.launch {
cache.emit(db.getItems()) // Warm Start: data redan i databasen
cache.emit(api.fetchItems()) // Bakgrundsuppdatering
}
}
}
Korrekt tillståndslagring är nyckelfaktorn som skiljer en bra Warm Start från en dålig. Användaren förväntar sig att återvända till appen och se samma sak som han lämnade — inklusive scrollposition, text i fält, valda flikar.
Systemet anropar onSaveInstanceState vid förstörelse av Activity, men INNAN processen kan dödas. I Bundle sparas endast enkla data (String, Int, Parcelable, Serializable). För komplexa data använd SavedStateHandle i ViewModel — det sparar och återställer automatiskt fält vid Warm Start. Till skillnad från onSaveInstanceState fungerar SavedStateHandle även om processen överlevde Warm Start (ViewModel förstörs inte). Exempel: för text i EditText använd SavedStateHandle.getLiveData(“text”) — texten sparas och återställs automatiskt.
Om processen inte dödades vid Warm Start, förblir ViewModel i minnet och onCleared anropas inte. Detta innebär att all data som laddades i föregående session är omedelbart tillgänglig. Men om processen dödades (enheten i deep sleep längre än 30 minuter) förstörs ViewModel och skapas på nytt med SavedStateHandle. För korrekt ViewModel-funktion vid Warm Start använd SavedStateHandle med fält som måste återställas i alla scenarier. Skillnad: ViewModel med @HiltViewModel stöder SavedStateHandle automatiskt.
| Mekanism | Processen lever | Processen dödad |
|---|---|---|
| ViewModel | Data i minnet | Förstörd, skapas på nytt |
| SavedStateHandle | Data i minnet | Återställs från Bundle |
| onSaveInstanceState | Anropas vid borttagning av Activity | Anropas inte |
| Room DB | Cache tillgänglig | Cache tillgänglig (disk) |
Ett av de vanligaste problemen med Warm Start — förlust av scrollposition. Användaren scrollade flödet till det 50:e elementet, minimerade appen, kom tillbaka — och ser början av listan. Lösning: spara layoutManager.onSaveInstanceState (sparar position och offset för första synliga elementet) och återställ det i onRestoreInstanceState. Du kan också spara den senaste synliga positionen i SharedPreferences med en datum/tid-nyckel för att snabbt återställa positionen vid Warm Start.
// Bevara scrollposition för RecyclerView
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) }
}
Två praktiska exempel på Warm Start-optimering: användning av SavedStateHandle i ViewModel och asynkron återställning av komplex data efter start.
SavedStateHandle sparar automatiskt fält i Bundle och återställer dem vid Warm Start. Användarprofilfältet (String, JSON) återställs utan extra förfrågningar till servern. Om processen dödades laddar SavedStateHandle det senast sparade tillståndet från 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 är inte null, UI utan loader
// Efter laddning: profile uppdateras i SavedStateHandle
Om den första skärmen innehåller en komplex layout (karta, gradient, flera listor), använd AsyncLayoutInflater för att expandera tunga element i bakgrunden. Medan layouten expanderas, visa en placeholder med shimmer-effekt. Detta är särskilt viktigt för Warm Start, där varje millisekund räknas. AsyncLayoutInflater arbetar i bakgrundstråden och levererar den färdiga Vyn via callback till huvudtråden.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Placeholder-layout för omedelbar rendering
setContentView(R.layout.placeholder_shimmer)
// Asynkron laddning av tung layout
AsyncLayoutInflater(this).inflate(
R.layout.activity_main_complex,
findViewById(R.id.container)
) { view, resId, parent ->
parent?.removeAllViews()
parent?.addView(view)
}
}
}
Vanliga frågor
Ja, om systemet vid Warm Start-tillfället beslutar att döda appens process (till exempel för att frigöra minne för en annan app), blir starten en Cold Start från början. Detta händer på enheter med 2–3 GB RAM när flera appar körs samtidigt. I praktiken är Warm Start endast garanterad inom 10–20 minuter efter minimering på medelklassenheter.
Ja, om processen inte dödades, förblir ViewModel i minnet och onCleared anropas inte. Detta är den viktigaste fördelen med Warm Start: all laddad data, nätverksförfrågningar, cache i ViewModel — omedelbart tillgänglig. Om processen dödades skapas ViewModel på nytt via ViewModelProvider.Factory eller @HiltViewModel och SavedStateHandle återställer sparade fält.
Teoretiskt är Warm Start alltid snabbare än Cold Start, men i praktiken finns det scenarier där skillnaden är minimal: om Application.onCreate är lätt (50 ms) och Activity.onCreate är tung (800 ms), då är Warm Start (800 ms) nästan lika med Cold Start (850 ms). I detta fall behöver du optimera inte Application, utan Activity.onCreate — det blir flaskhalsen för Warm Start.
SplashScreen API på Android 12+ visar en system-splash (ikon på färgad bakgrund) omedelbart vid start — både för Cold och Warm Start. För Warm Start visas splash endast i 100–300 ms, varefter den ersätts av appens UI. SplashScreen i sig påskyndar inte starten, men maskerar tiden för Activity-skapande och förbättrar uppfattningen.
Ja, eftersom Warm Start förekommer 2–3 gånger oftare än Cold Start. Om Cold Start tar 1,2 sekunder och Warm Start 600 ms, tar 40% av starterna (Warm) fortfarande 0,6 sekunder, vilket är märkbart. Optimering av Warm Start till 200–300 ms ger användaren en känsla av omedelbar återkomst. På enheter med 6+ GB RAM kan Warm Start utgöra upp till 80% av alla starter och dess optimering blir en prioritet.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också