onDestroy: cos'è, conclusione del lavoro di Activity in Android

Autore: IT Sectr Pubblicato: 2026-03-04 Tempo di lettura: 8 min

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 — l'ultima chiamata prima di distruggere un'Activity o un Fragment, destinata alla pulizia finale delle risorse.
  • La chiamata a onDestroy non è garantita durante la morte del processo da parte del sistema — non affidarti ad essa per salvare dati critici.
  • In onDestroy devi annullare le attività in background, chiudere socket e database, e pulire il ViewModelStore.
  • Differenza da onStop: onStop — perdita di visibilità (l'Activity rimane in memoria), onDestroy — distruzione completa.
  • isFinishing() in onDestroy mostra se l'Activity termina per comando dell'utente (finish()) o per decisione del sistema.

onDestroy: cos'è in Android?

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:

  • Chiamata esplicita a finish() — l'utente ha premuto “Indietro” o lo sviluppatore ha chiamato finishActivity().
  • Rotazione dello schermo — l'Activity viene distrutta e ricreata con una nuova configurazione.
  • Cambiamento di configurazione — tastiera, cambio lingua, cambio dimensione schermo (multi-finestra).
  • Decisione del sistema — Android uccide l'Activity per liberare risorse (ma onDestroy potrebbe non essere chiamato).

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).

Quando onDestroy viene chiamato — e quando non viene chiamato

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:

  • L'utente preme il pulsante “Indietro” — Activity.finish() → onPause → onStop → onDestroy.
  • Rotazione dello schermo — l'Activity viene distrutta (onPause → onStop → onDestroy), poi ricreata.
  • Cambiamento di configurazione — impostazione di sistema che richiede la ricreazione dell'Activity.
  • Chiamata a finishAffinity() — termina tutte le Activities nello stack.
  • Rimozione di un Fragment dal FragmentManager — il Fragment riceve: onPause → onStop → onDestroyView → onDestroy → onDetach.

Quando onDestroy NON viene chiamato:

  • Morte del processo da parte del sistema — Android uccide l'intero processo dell'applicazione quando la memoria è insufficiente. L'Activity non riceve onDestroy perché il processo termina a livello di kernel Linux.
  • Terminazione anomala — un'eccezione non catturata nel thread principale uccide l'applicazione senza chiamare onDestroy.
  • Arresto forzato — l'utente arresta forzatamente l'applicazione nelle impostazioni.

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 in Activity e Fragment: punti in comune e differenze

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).

ComponenteMetodi di distruzioneOrdineViewModel sopravvive
ActivityonDestroyonPause → onStop → onDestroyNo (solo se ViewModelStore non viene salvato)
FragmentonDestroyView, onDestroy, onDetachonPause → onStop → onDestroyView → onDestroy → onDetachSì, 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.

Cosa fare in onDestroy: lista di controllo per la pulizia

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:

  • Annullare coroutine e Flow — annulla i job che non sono legati a viewModelScope. viewModelScope viene annullato automaticamente, ma lifecycleScope è legato al ciclo di vita dell'Activity.
  • Chiudere socket e canali — WebSocket (OkHttp), BluetoothSocket, ServerSocket. Tenerli aperti dopo la distruzione è una perdita di risorse di sistema.
  • Chiudere file e flussi — FileInputStream, FileOutputStream, Cursor. Un Cursor può causare ANR su ContentProvider se non viene chiuso.
  • Annullare l'iscrizione di ContentObserver — se l'Activity sta monitorando i cambiamenti di contenuto (contatti, libreria multimediale).
  • Annullare la registrazione di BroadcastReceiver — i receiver registrati dinamicamente devono essere annullati.
  • Chiudere il database — Room chiude automaticamente la connessione quando l'Application viene distrutta, ma SQLiteDatabase diretto richiede close() manuale.

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.

onDestroy e ViewModel: lavoro congiunto

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:

  • Activity: onPause → onStop → onDestroy (Activity distrutta).
  • ViewModel: NON distrutto — il ViewModelStore viene salvato e passato alla nuova Activity.
  • Nuova Activity: onCreate → onStart → onResume, riceve lo stesso ViewModel.

Durante finish() (l'utente ha premuto “Indietro”):

  • Activity: onPause → onStop → onDestroy.
  • ViewModel: onCleared() — chiamato dopo onDestroy dell'Activity.
  • Tutte le coroutine di viewModelScope vengono annullate automaticamente.

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.

Esempi di codice con onDestroy in Kotlin

Esempio 1: onDestroy Activity con annullamento di coroutine lifecycleScope

Mostra la corretta gestione di lifecycleScope in un'Activity: una coroutine viene avviata per monitorare lo stato della rete e annullata in onDestroy.

kotlin
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.

Esempio 2: onDestroy Fragment con pulizia dei riferimenti alla View

Un Fragment pulisce correttamente i riferimenti alla View in onDestroyView, prevenendo perdite di memoria dovute a chiusure.

kotlin
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.

Esempio 3: Verifica di isFinishing in onDestroy

Usare isFinishing() permette di distinguere se l'Activity termina per comando dell'utente o per ricreazione.

kotlin
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

Può onDestroy non essere chiamato?

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.

Qual è la differenza tra onDestroy e finish()?

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.

Devo chiamare super.onDestroy() in Fragment?

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.

Quando viene chiamato onCleared() in ViewModel rispetto a onDestroy?

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().

Posso avviare un Service da onDestroy?

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

  • onDestroy — il callback finale del ciclo di vita di Activity e Fragment, chiamato prima della completa distruzione del componente.
  • La chiamata a onDestroy non è garantita durante la morte del processo — circa il 5–8% delle terminazioni avvengono senza di essa.
  • In onDestroy devi liberare: callback di rete, socket, flussi di file, BroadcastReceiver, ContentObserver.
  • ViewModel.onCleared() viene chiamato dopo onDestroy dell'Activity — viewModelScope viene annullato automaticamente.
  • onDestroyView in Fragment (separato da onDestroy) — il luogo giusto per nullificare i riferimenti alla View.
  • Verificare isFinishing() in onDestroy permette di distinguere la terminazione finish() dalla ricreazione dovuta a cambiamenti di configurazione.
  • Non affidarti a onDestroy per salvare dati — usa onPause o onSaveInstanceState.

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.

Discuti il progetto

Leggi anche