Cold Start è il ciclo completo di avvio di un'applicazione Android che parte da uno stato zero, quando il processo dell'applicazione non esiste in memoria e l'Activity non è stata creata. Il sistema crea un nuovo processo, carica le classi, inizializza l'Application, crea l'Activity ed esegue il primo disegno. Secondo Google, 2024, l'avvio a freddo sui dispositivi di fascia media può richiedere da 1 a 5 secondi e ogni 100 ms di ritardo riducono la probabilità di fidelizzazione dell'utente del 3%.
Punti chiave
Cold Start (avvio a freddo) è uno scenario in cui un'applicazione Android viene avviata dallo stato più iniziale: il sistema operativo crea un nuovo processo (fork da Zygote), alloca memoria, carica il codice DEX in ART, inizializza le classi e crea un'istanza di Application, quindi la prima Activity. Prima dell'avvio dell'app, non ci sono dati su di essa nella memoria del dispositivo, tranne le immagini della classe memorizzate nella cache se viene utilizzato Background Dexopt.
L'avvio a freddo si verifica in tre casi: al primo avvio dopo l'installazione dell'app, all'avvio dopo il riavvio del dispositivo e all'avvio dopo che il sistema ha rimosso il processo per mancanza di memoria. Sui dispositivi con 2–4 GB di RAM, il sistema rimuove i processi in background in modo abbastanza aggressivo, quindi Cold Start può verificarsi ogni volta che l'utente torna all'app dopo diverse ore di inattività. Su Android 12+, il sistema può mantenere un processo congelato (freeze / cached), ma con il risparmio attivo della memoria (OOM-killer), il processo verrà terminato.
Secondo Google (rapporto Find My Device, 2023), il 65% degli utenti chiude un'app se non si apre entro 3 secondi. Per i social network e i messenger, dove gli utenti tornano decine di volte al giorno, Cold Start influisce direttamente sulla fidelizzazione. In Google Play Console, la metrica Cold Start fa parte della sezione Android Vitals e viene visualizzata come uno degli indicatori ANR e di prestazione. Un'app che supera la soglia di Cold Start “pessimo” (più di 5 secondi sul 25% dei dispositivi) riceve un avviso nella console e può essere declassata nei risultati di ricerca.
Android distingue tre tipi di avvio dell'app, ciascuno con durata, impatto sull'UX e approcci di ottimizzazione diversi. Comprendere la differenza è essenziale per scegliere la giusta strategia di profilazione.
| Tipo di avvio | Stato del processo | Application.onCreate | Tempo tipico |
|---|---|---|---|
| Cold | Nessun processo | Eseguito | 1–5 secondi |
| Warm | Processo esistente, nessuna Activity | Non eseguito | 200–600 ms |
| Hot | Processo + Activity in memoria | Non eseguito | < 200 ms |
Warm Start si verifica quando il processo dell'app esiste già in background, ma l'Activity è stata distrutta (ad esempio, l'utente è tornato dopo una lunga pausa e il sistema ha liberato la memoria dell'Activity). Hot Start — quando l'utente minimizza l'app e la riapre immediatamente: l'Activity è in pausa e il ripristino richiede un tempo minimo. Per l'utente, Cold Start è il tipo di avvio più evidente e la sua ottimizzazione porta il maggior miglioramento dell'UX.
Cold Start può diventare Warm Start dopo che l'app è stata avviata almeno una volta — ART memorizza nella cache le immagini delle classi compilate (Image in Boot Profile) e il successivo caricamento DEX è più veloce. Pertanto, il secondo avvio dopo il primo Cold Start è generalmente del 20–40% più veloce. Se l'app utilizza Baseline Profiles, i profili vengono caricati al primo avvio e il secondo avvio può essere ancora più veloce: Google Play, che ha pubblicato Baseline Profiles, ha accelerato Cold Start del 30% sui dispositivi con Android 12+.
Cold Start consiste in fasi rigorosamente definite, ciascuna delle quali può essere misurata e ottimizzata indipendentemente. Conoscere le fasi aiuta a determinare in quale stadio l'app sta perdendo tempo. Google identifica quattro fasi principali: creazione del processo, inizializzazione dell'Application, creazione dell'Activity e primo fotogramma.
Il sistema Android (ActivityManagerService) crea un nuovo processo tramite fork dal processo Zygote. Zygote è un processo precaricato con le classi comuni di Android. Il fork richiede 30–80 ms — questo tempo è fuori dal controllo dell'app. Dopo il fork, viene avviato ActivityThread — l'istanza del ciclo principale dell'applicazione. In questa fase avviene anche il caricamento delle classi tramite ClassLoader e ART inizia a interpretare il primo bytecode. Se l'app utilizza molti inizializzatori statici, questa fase può prolungarsi.
Subito dopo l'avvio di ActivityThread, viene chiamato Application.onCreate. Qui è dove gli sviluppatori commettono più spesso l'errore di inizializzare tutto in una volta: Crashlytics, Firebase, client di rete, database, componenti Dagger, contenitori DI. Ciascuna di queste inizializzazioni blocca il thread principale. Se Application.onCreate richiede 500 ms, l'utente vede una schermata bianca (o nera) per mezzo secondo. La durata ottimale di questa fase è inferiore a 200 ms su un dispositivo di fascia media.
Dopo l'inizializzazione dell'Application, viene creata un'istanza di Activity (MainActivity o Launcher Activity). Viene chiamato Activity.onCreate, dove si verificano setContentView, l'inizializzazione dei fragment, la configurazione di ViewModel e la sottoscrizione a LiveData/Flow. Se onCreate carica dati (SharedPreferences, SQLite, API) in modo sincrono sul thread principale, la fase si estende. L'obiettivo è mantenere onCreate entro 200–400 ms su un dispositivo di fascia media.
Dopo il completamento di onCreate, inizia il primo rendering: misura, layout, draw. Questo momento è chiamato TTFD (Time To First Draw). Se l'app utilizza una schermata splash (tramite SplashScreen API su Android 12+ o tramite tema), il rendering può avvenire più velocemente, ma l'utente aspetterà comunque che lo splash scompaia. La TTFD ideale per Cold Start è inferiore a 1,5 secondi.
Misurare Cold Start richiede strumenti speciali, poiché la registrazione normale (Log.d) inizia a funzionare solo dopo la creazione dell'Application e la tempistica del fork e del caricamento delle classi rimane inaccessibile. Google raccomanda tre metodi: comandi ADB, Android Vitals e macro di performance personalizzate.
Il metodo più semplice e riproducibile è il comando adb shell am start -S -W. Il flag -S ferma forzatamente l'app prima dell'avvio (garantisce Cold Start). Il comando restituisce tre metriche: ThisTime (tempo di avvio dell'Activity), TotalTime (tempo totale inclusivo dell'avvio del processo) e WaitTime (tempo inclusivo di tutti i ritardi di Activity Manager). Per misurazioni pulite, effettuare 5–7 letture e utilizzare la mediana — le letture singole sono soggette a rumore (CPU throttling, carico in background).
# Cold Start forzato con misurazione
$ adb shell am start -S -W \
com.example.app/.MainActivity
# Output del comando:
# ThisTime: 1842 ms
# TotalTime: 1842 ms
# WaitTime: 1855 ms
Google Play Console raccoglie metriche anonime da tutti i dispositivi in cui l'app è installata. Nella sezione Android Vitals → Launch time, viene visualizzata la distribuzione mediana di Cold Start per modello di dispositivo e versione Android. Questo è l'unico modo per vedere le metriche reali sui dispositivi degli utenti, non solo sui dispositivi di test. Se Cold Start supera 5 secondi su Redmi 9A (2 GB RAM) e 1,2 secondi su Pixel 8, il problema è la dimensione della memoria e il numero di classi. Google mostra anche il ritardo percepibile dall'utente basato sul 25esimo percentile.
Google Jetpack Macrobenchmark (libreria androidx.benchmark) consente di scrivere test strumentati di avvio dell'app. Il test installa l'app, la avvia da uno stato a freddo e misura il tempo fino al primo fotogramma. Macrobenchmark esegue automaticamente 20 iterazioni, scarta i valori anomali e mostra percentili stabili. Per CI/CD, puoi confrontare la baseline e l'avvio corrente — se il tempo aumenta, la pipeline CI può fallire.
Ottimizzare Cold Start è un lavoro sistematico che interessa diversi livelli dell'app: codice, risorse, configurazione di build e architettura di inizializzazione. Google raccomanda di iniziare dalla parte più costosa — Application.onCreate — e procedere verso i dettagli più piccoli.
Sposta tutta l'inizializzazione non richiesta all'avvio fuori da Application.onCreate al primo punto di utilizzo. Firebase, Crashlytics, SDK di analisi, notifiche push, componenti DI — tutto può essere inizializzato dopo il rendering della prima schermata. Usa Lazy (by lazy) in Kotlin o l'inizializzazione tramite ContentProvider con una chiamata esplicita initialize(context). Secondo Google (Android Performance, 2023), l'inizializzazione pigra riduce Cold Start del 40–60% per le app che utilizzano 5+ SDK.
Baseline Profiles sono la compilazione AOT di classi e metodi critici utilizzati all'avvio dell'app. Senza Baseline Profiles, ART interpreta il codice DEX o lo compila tramite JIT, richiedendo tempo. Con i profili, ART compila i metodi specificati in codice nativo (AOT) durante l'installazione dell'app. Google afferma che Baseline Profiles accelerano Cold Start del 15–40% su Android 9+ e fino al 60% con le ottimizzazioni ART di Android 12+. Per creare profili, usa il plugin androidx.benchmark:benchmark-baseline-profile-gradle-plugin.
La libreria androidx.startup consente di ordinare l'inizializzazione dei componenti ed eseguirla in un unico ContentProvider. Invece di più ContentProvider di diverse librerie (ciascuno aggiunge 1–2 ms all'avvio a freddo), App Startup li unisce in un grafo di dipendenze e inizializza rigorosamente secondo necessità. All'avvio vengono eseguiti solo i componenti contrassegnati con @Initializer che sono necessari per la prima schermata. Per gli altri, viene impostato il flag needEarlyInit = false — vengono avviati dopo il primo rendering.
// App Startup Initializer — inizializzazione dopo l'avvio
class AnalyticsInitializer : Initializer<Unit> {
override fun create(context: Context) {
Analytics.init(context)
}
override fun dependencies() = listOf<Class<out Initializer<*>>>()
}
// In AndroidManifest.xml marcare come opzionale
// <meta-data android:name="AnalyticsInitializer"
// android:value="false" />
La dimensione del file DEX influisce direttamente sul tempo di caricamento di ART. Usa R8/ProGuard per offuscamento e rimozione del codice morto (MinifyEnabled = true). Attiva android:extractNativeLibs="false" nel manifest in modo che l'APK non decomprima i file .so durante l'installazione. Per progetti con più di 10 tracciamenti di riferimento, aggiungi startup-priority solo per la prima schermata. Ogni metodo extra in DEX aggiunge 0,5–2 ms al caricamento e per le app con più di 50k metodi (multidex con primary dex) — fino a 300 ms.
Android Vitals in Google Play Console (sezione Launch time) raccoglie dati da tutti i dispositivi in cui l'app è installata, a condizione che l'utente abbia acconsentito alla diagnostica anonima. Le metriche sono divise in tre categorie: “buono”, “moderato”, “pessimo”, a seconda del tempo di Cold Start.
Google definisce Cold Start “pessimo” come un tempo superiore a 5 secondi su qualsiasi dispositivo. Tuttavia, in pratica, per i dispositivi di punta (Snapdragon 8 Gen), un buon tempo è inferiore a 1,5 secondi, per la fascia media — inferiore a 2,5 secondi, per la fascia bassa — inferiore a 4 secondi. Android Vitals mostra la mediana per ciascun modello di dispositivo, permettendo di capire su quali dispositivi l'app si avvia lentamente. Se Cold Start è pessimo sui dispositivi Samsung A-series o Xiaomi Redmi, la causa è molto spesso la memoria flash lenta e la scarsa RAM (l'accelerazione tramite Baseline Profiles dà il maggior effetto proprio su tali dispositivi).
Oltre alla visualizzazione nella console, la metrica Cold Start influisce sulla valutazione della qualità dell'app in Google Play Search. Le app con un'alta percentuale di avvii “pessimi” ricevono un'etichetta “Avviso di prestazioni” sulla pagina di installazione, riducendo la conversione. Secondo Google (Android Performance Playbook, 2024), le app che hanno risolto i problemi di Cold Start hanno aumentato la conversione di installazione in media del 5% e migliorato la fidelizzazione (D1) del 3–7%.
Per un monitoraggio più dettagliato, usa Firebase Performance Monitoring. Tiene traccia di Cold Start a livello di sessione, suddiviso per versione dell'app e versione di Android. A differenza di Android Vitals, Firebase mostra un diagramma di traccia del tempo speso per fase. Ad esempio, puoi vedere che nella versione 3.2.0, Application.onCreate ha richiesto 800 ms (a causa di una nuova libreria di notifiche push), mentre nella versione 3.2.1 — 200 ms (dopo la correzione).
Di seguito sono riportati due esempi pratici che accelerano direttamente Cold Start: spostare l'inizializzazione degli SDK dopo l'avvio e utilizzare SplashScreen API.
Un errore tipico è inizializzare tutti gli SDK in Application.onCreate. Di seguito è mostrato come spostare l'inizializzazione non critica in una coroutine che viene avviata dopo il disegno del primo fotogramma. Importante: Firebase, Crashlytics e gli SDK di segnalazione crash devono essere inizializzati all'avvio — non possono essere ritardati perché catturano i crash durante l'inizializzazione di altri componenti. Per il resto, usa lifecycleScope nella prima Activity.
// ❌ Pessimo — tutta l'inizializzazione in Application.onCreate
class App : Application() {
override fun onCreate() {
super.onCreate()
Firebase.init(this) // critico
Analytics.init(this) // può essere dopo
Database.init(this) // può essere dopo
ImageLoader.init(this) // può essere dopo
}
}
// ✅ Buono — Firebase all'avvio, il resto after inflate
class App : Application() {
override fun onCreate() {
super.onCreate()
Firebase.init(this)
}
}
// In MainActivity dopo il primo fotogramma:
lifecycleScope.launchWhenResumed {
initializeNonCriticalSdks()
}
Su Android 12+, usa l'API ufficiale SplashScreen che mostra uno splash di sistema (icona dell'app su sfondo scuro/chiaro) immediatamente all'avvio del processo. Questo nasconde il tempo di inizializzazione all'utente — vede uno splash invece di una schermata bianca. Per i dispositivi più vecchi, usa theme-based splash (Theme.SplashScreen negli stili). Importante: lo splash non dovrebbe durare più di 300 ms — se l'app non è pronta entro quel momento, disegna uno scheletro “persistente” (shimmer) e mostra l'avanzamento del caricamento.
// SplashScreen API — Android 12+
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition {
isReady.value == false
}
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
// Splash basato su tema (Android 5-11)
// In themes.xml:
// <style name="Theme.App.Starting" parent="Theme.SplashScreen">
// <item name="windowSplashScreenBackground">@color/white</item>
// <item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item>
// </style>
Domande frequenti
L'emulatore utilizza un potente computer host ed emula il processore con accelerazione hardware (HAXM / WHPX). I dispositivi fisici, specialmente quelli di fascia bassa (memoria eMMC invece di UFS), hanno I/O molto più lento. Si consiglia di misurare Cold Start su un dispositivo fisico di fascia media per ottenere dati realistici.
Secondo le raccomandazioni di Google, il Cold Start mediano dovrebbe essere inferiore a 2 secondi sui dispositivi di fascia media. Per i flagship — inferiore a 1,5 secondi. Per i dispositivi di fascia bassa (2 GB RAM) sono accettabili fino a 4 secondi, ma si consiglia di ottimizzare a 3 secondi. I valori superiori a 5 secondi sono considerati critici.
Indirettamente — sì. Se il manifest contiene un'icona vettoriale (AdaptiveIcon), deve essere compilata in un drawable all'avvio. Se l'icona contiene percorsi complessi (pathData con decine di curve), la compilazione richiede 10–30 ms. Usa VectorDrawable con pathData ottimizzato (tramite SVGOMG o Android Studio Vector Asset).
Sì, se un Feature Module (Android App Bundle) viene caricato su richiesta, il suo Cold Start viene misurato dal momento in cui si tocca la funzionalità al primo fotogramma. I moduli su richiesta vengono caricati tramite Play Core Library e la loro installazione aggiunge 500–3000 ms al tempo di avvio. Ottimizza il codice della funzionalità come faresti con il modulo principale.
Le app con più di 64k metodi richiedono Multidex. Ciò significa che ART deve caricare più file DEX, aumentando il tempo di Cold Start di 200–800 ms a seconda del numero di file classes.dex. Usa minSdk 21+ (ART con supporto nativo multidex) e configura primary dex tramite --main-dex-list per mantenere le classi critiche nel primo file DEX.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche