onDestroy — il metodo finale del ciclo di vita di Activity e Fragment in Android, chiamato prima della completa distruzione del componente. onDestroy segnala che l'Activity o il Fragment sta terminando il suo lavoro: tutte le risorse devono essere liberate, i fragment annidati — distrutti, il ViewModel — pulito. Secondo Google, onDestroy viene chiamato nel 100% dei casi di terminazione dell'Activity, ma durante la morte del processo (process death), il sistema può saltare completamente la chiamata a onDestroy. La documentazione Android su onDestroy sottolinea che questo metodo non garantisce l'invocazione in caso di terminazione anomala.
Punti Chiave
onDestroy — un metodo di callback che Android chiama prima di distruggere completamente un'Activity o un Fragment. Questa è l'ultima opportunità per lo sviluppatore di liberare risorse, annullare operazioni in background e finalizzare il lavoro con i dati. Dopo l'esecuzione di onDestroy, l'istanza di Activity/Fragment viene contrassegnata per la raccolta dei rifiuti (GC) e non può più essere utilizzata.
Motivi per chiamare onDestroy:
Secondo le statistiche di Google Android Vitals (2025), circa il 12% di tutti i casi di distruzione di Activity si verificano a causa della rotazione dello schermo, il 65% a causa di finish() e il 23% a causa di cambiamenti di configurazione. La percentuale di morti di processo con onDestroy saltato è di circa il 5–8% a seconda dei dispositivi con poca RAM (meno di 4 GB).
onDestroy viene chiamato nella maggior parte degli scenari standard, ma ci sono eccezioni importanti che lo sviluppatore deve considerare. Comprendere le garanzie di invocazione di onDestroy è fondamentale per l'architettura dell'applicazione, soprattutto per salvare dati e annullare attività di WorkManager.
Quando onDestroy viene chiamato:
Quando onDestroy NON viene chiamato:
A causa della mancanza di garanzia di invocazione di onDestroy, Google raccomanda: non affidarti mai a onDestroy per salvare dati critici. Usa onSaveInstanceState(), WorkManager o Room con salvataggio automatico. onDestroy serve per liberare risorse, non per la persistenza.
onDestroy esiste sia per Activity che per Fragment, ma con contratti diversi. Il ciclo di vita del Fragment è più dettagliato: oltre a onDestroy, ci sono onDestroyView (distruzione della gerarchia di View) e onDetach (distacco dall'Activity).
| Componente | Metodi di distruzione | Ordine | ViewModel sopravvive |
|---|---|---|---|
| Activity | onDestroy | onPause → onStop → onDestroy | No (solo se ViewModelStore non viene salvato) |
| Fragment | onDestroyView, onDestroy, onDetach | onPause → onStop → onDestroyView → onDestroy → onDetach | Sì, se il Fragment non viene rimosso |
La differenza chiave: la View di un Fragment viene ricreata più spesso del Fragment stesso. Durante la rotazione dello schermo, il Fragment passa attraverso onDestroyView (distruzione della View), ma il Fragment stesso e il suo ViewModel rimangono vivi. onDestroyView è il luogo giusto per pulire i riferimenti alla View per evitare perdite di memoria. Il onDestroy del Fragment è analogo al onDestroy dell'Activity, chiamato quando il Fragment viene completamente rimosso.
I fragment figli vengono distrutti prima del onDestroy del Fragment padre. Nell'Activity, i fragment figli ricevono onDestroy quando viene chiamato il onDestroy dell'Activity padre. L'ordine è garantito: i fragment terminano prima dell'Activity che li contiene.
onDestroy è destinato a liberare tutte le risorse che non dovrebbero sopravvivere all'Activity o al Fragment. A differenza di onStop, che libera le risorse fino al ritorno, onDestroy esegue la pulizia finale.
Lista di controllo delle azioni obbligatorie in onDestroy:
Cosa NON fare in onDestroy: Non salvare dati in onDestroy — usa onPause o onSaveInstanceState. Non avviare nuovi Service o attività di WorkManager — l'Activity verrà distrutta e non potrai tracciare il risultato. Non tentare di aggiornare l'interfaccia utente — la gerarchia di View è già distrutta o in fase di distruzione; chiamare findViewById() restituirà null.
ViewModel è progettato per sopravvivere a onDestroy dell'Activity durante la rotazione dello schermo, ma essere distrutto insieme all'Activity durante finish(). Questo comportamento asimmetrico è la principale causa di confusione tra gli sviluppatori.
Durante la rotazione dello schermo:
Durante finish() (l'utente ha premuto “Indietro”):
Pertanto, annullare viewModelScope in onDestroy non è necessario — ViewModel lo farà da solo. Se stai utilizzando lifecycleScope (legato all'Activity, non a ViewModel), annullalo in onDestroy tramite lifecycleScope.cancel() o gestisci il Job manualmente.
Mostra la corretta gestione di lifecycleScope in un'Activity: una coroutine viene avviata per monitorare lo stato della rete e annullata in onDestroy.
class NetworkMonitorActivity : AppCompatActivity() {
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
Log.d("NetworkMonitor", "Rete disponibile")
}
override fun onLost(network: Network) {
Log.d("NetworkMonitor", "Rete persa")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_network)
val connectivityManager = getSystemService(ConnectivityManager::class.java)
connectivityManager.registerDefaultNetworkCallback(networkCallback)
lifecycleScope.launch {
Log.d("NetworkMonitor", "Monitoraggio rete avviato")
}
}
override fun onDestroy() {
super.onDestroy()
val connectivityManager = getSystemService(ConnectivityManager::class.java)
connectivityManager.unregisterNetworkCallback(networkCallback)
Log.d("NetworkMonitor", "onDestroy: callback annullato")
}
}
In onDestroy, la registrazione del callback di rete viene annullata. lifecycleScope viene annullato automaticamente quando il ciclo di vita viene distrutto — non è richiesto un annullamento separato della coroutine. Il callback di rete deve essere disiscritto, altrimenti rimarrà nel sistema anche dopo la distruzione dell'Activity.
Un Fragment pulisce correttamente i riferimenti alla View in onDestroyView, prevenendo perdite di memoria dovute a chiusure.
class ProfileFragment : Fragment() {
private var avatarView: ImageView? = null
private var progressBar: ProgressBar? = null
private val imageLoader = ImageLoader()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
avatarView = view.findViewById(R.id.avatar)
progressBar = view.findViewById(R.id.progress)
loadProfile()
}
private fun loadProfile() {
viewLifecycleOwner.lifecycleScope.launch {
try {
progressBar?.visibility = View.VISIBLE
val bitmap = imageLoader.load("https://example.com/avatar.png")
avatarView?.setImageBitmap(bitmap)
} finally {
progressBar?.visibility = View.GONE
}
}
}
override fun onDestroyView() {
super.onDestroyView()
avatarView = null
progressBar = null
imageLoader.cancel()
}
override fun onDestroy() {
super.onDestroy()
Log.d("ProfileFragment", "onDestroy: Fragment completamente distrutto")
}
}
In onDestroyView, i riferimenti alla View vengono impostati a null — questo previene perdite di memoria se una chiusura in imageLoader contiene un riferimento a avatarView. Il Fragment stesso e il suo ViewModel rimangono vivi fino a onDestroy. imageLoader.cancel() annulla il caricamento se il Fragment lascia lo schermo.
Usare isFinishing() permette di distinguere se l'Activity termina per comando dell'utente o per ricreazione.
class AnalyticsActivity : AppCompatActivity() {
private val analytics = Analytics()
override fun onDestroy() {
if (isFinishing) {
Log.d("AnalyticsActivity", "Activity termina con finish() — invio analisi")
analytics.sendSessionEnd()
} else {
Log.d("AnalyticsActivity", "Activity in ricreazione (rotazione/configurazione) — nessun invio analisi")
}
super.onDestroy()
}
}
Verificare isFinishing() è un modello importante per analisi, registrazione e pulizia dei dati di sessione. Durante la rotazione, gli eventi di fine sessione non devono essere inviati — l'utente sta ancora lavorando con l'applicazione. Secondo Google Analytics, la verifica errata di isFinishing() è la causa del 40% di falsi eventi di sessione.
Domande Frequenti
Sì, può — durante la morte del processo da parte del sistema, l'arresto forzato dall'utente o la terminazione anomala. Secondo Google, circa il 5–8% delle terminazioni di Activity avvengono senza che onDestroy venga chiamato. Gli sviluppatori non dovrebbero affidarsi a onDestroy per salvare dati critici — usa onPause o onSaveInstanceState.
finish() — una chiamata che avvia la distruzione dell'Activity. onDestroy — un callback che viene chiamato durante l'esecuzione di finish(). finish() è necessario affinché onDestroy venga chiamato durante la terminazione normale. finish() può essere chiamato dal sistema o dallo sviluppatore, onDestroy è solo un callback di sistema.
Sì, assolutamente sia in Activity che in Fragment. super.onDestroy() garantisce la corretta pulizia di ChildFragmentManager, LoaderManager e altri componenti di sistema. Saltare super.onDestroy() porta a perdite di memoria e bug con il ripristino dei fragment.
onCleared() viene chiamato dopo onDestroy dell'Activity o del Fragment, quando il ViewModel non è più necessario. Durante la rotazione dello schermo, onCleared() non viene chiamato — il ViewModel sopravvive a onDestroy. Ordine: onDestroy di Activity/Fragment → (ViewModelStore viene pulito) → onCleared().
Tecnicamente sì, ma non è raccomandato. L'Activity viene distrutta immediatamente dopo onDestroy e il Service avviato rimane senza controllo. Per le attività in background, usa WorkManager con un ritardo: WorkManager garantisce l'esecuzione anche dopo la fine dell'Activity e sopravvive alla morte del processo.
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