onDestroy — el método final del ciclo de vida de Activity y Fragment en Android, llamado antes de la destrucción completa del componente. onDestroy señala que la Activity o Fragment está finalizando su trabajo: todos los recursos deben liberarse, los fragmentos anidados — destruirse, el ViewModel — limpiarse. Según Google, onDestroy se llama en el 100% de los casos de terminación de Activity, pero durante la muerte del proceso (process death), el sistema puede omitir la llamada a onDestroy por completo. Documentación de Android sobre onDestroy enfatiza que este método no garantiza la invocación durante una terminación anormal.
Puntos Clave
onDestroy — un método de callback que Android llama antes de destruir completamente una Activity o Fragment. Esta es la última oportunidad para que el desarrollador libere recursos, cancele operaciones en segundo plano y finalice el trabajo con datos. Después de ejecutar onDestroy, la instancia de Activity/Fragment se marca para recolección de basura (GC) y ya no puede utilizarse.
Razones para llamar a onDestroy:
Según las estadísticas de Google Android Vitals (2025), aproximadamente el 12% de todos los casos de destrucción de Activity ocurren debido a la rotación de pantalla, el 65% debido a finish() y el 23% debido a cambios de configuración. El porcentaje de muertes de proceso con omisión de onDestroy es de aproximadamente 5–8% dependiendo de los dispositivos con poca RAM (menos de 4 GB).
onDestroy se llama en la mayoría de los escenarios estándar, pero hay excepciones importantes que el desarrollador debe considerar. Comprender las garantías de la invocación de onDestroy es crítico para la arquitectura de la aplicación, especialmente para guardar datos y cancelar tareas de WorkManager.
Cuándo se llama a onDestroy:
Cuándo NO se llama a onDestroy:
Debido a la falta de garantía de invocación de onDestroy, Google recomienda: nunca confíes en onDestroy para guardar datos críticos. Usa onSaveInstanceState(), WorkManager o Room con guardado automático. onDestroy es para liberar recursos, no para persistencia.
onDestroy existe tanto para Activity como para Fragment, pero con diferentes contratos. El ciclo de vida de Fragment es más detallado: además de onDestroy, existen onDestroyView (destrucción de la jerarquía de View) y onDetach (desvinculación de la Activity).
| Componente | Métodos de destrucción | Orden | ViewModel sobrevive |
|---|---|---|---|
| Activity | onDestroy | onPause → onStop → onDestroy | No (solo si ViewModelStore no se guarda) |
| Fragment | onDestroyView, onDestroy, onDetach | onPause → onStop → onDestroyView → onDestroy → onDetach | Sí, si el Fragment no se elimina |
La diferencia clave: la View de un Fragment se recrea con más frecuencia que el propio Fragment. Durante la rotación de pantalla, el Fragment pasa por onDestroyView (destrucción de la View), pero el Fragment en sí y su ViewModel permanecen vivos. onDestroyView es el lugar adecuado para limpiar las referencias a View y evitar fugas de memoria. El onDestroy de Fragment es análogo al onDestroy de Activity, llamado cuando el Fragment se elimina por completo.
Los fragments hijos se destruyen antes del onDestroy del Fragment padre. En la Activity, los fragments hijos reciben onDestroy cuando se llama al onDestroy de la Activity padre. El orden está garantizado: los fragments finalizan antes que la Activity que los contiene.
onDestroy está destinado a liberar todos los recursos que no deben sobrevivir a la Activity o Fragment. A diferencia de onStop, que libera recursos hasta el regreso, onDestroy realiza la limpieza final.
Lista de verificación de acciones obligatorias en onDestroy:
Qué NO hacer en onDestroy: No guardes datos en onDestroy — usa onPause u onSaveInstanceState. No inicies nuevos Service o tareas de WorkManager — la Activity se destruirá y no podrás rastrear el resultado. No intentes actualizar la UI — la jerarquía de View ya está destruida o en proceso de destrucción; llamar a findViewById() devolverá null.
ViewModel está diseñado para sobrevivir a onDestroy de Activity durante la rotación de pantalla, pero ser destruido junto con la Activity durante finish(). Este comportamiento asimétrico es la principal causa de confusión entre los desarrolladores.
Durante la rotación de pantalla:
Durante finish() (el usuario presionó “Atrás”):
Por lo tanto, cancelar viewModelScope en onDestroy no es necesario — ViewModel lo hará por sí mismo. Si estás usando lifecycleScope (vinculado a la Activity, no a ViewModel), cancélalo en onDestroy mediante lifecycleScope.cancel() o gestiona el Job manualmente.
Demuestra la gestión correcta de lifecycleScope en una Activity: se lanza una corrutina para monitorear el estado de la red y se cancela en onDestroy.
class NetworkMonitorActivity : AppCompatActivity() {
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
Log.d("NetworkMonitor", "Red disponible")
}
override fun onLost(network: Network) {
Log.d("NetworkMonitor", "Red perdida")
}
}
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", "Monitoreo de red iniciado")
}
}
override fun onDestroy() {
super.onDestroy()
val connectivityManager = getSystemService(ConnectivityManager::class.java)
connectivityManager.unregisterNetworkCallback(networkCallback)
Log.d("NetworkMonitor", "onDestroy: callback cancelado")
}
}
En onDestroy, se cancela el registro del callback de red. lifecycleScope se cancela automáticamente cuando se destruye el ciclo de vida — no se requiere cancelación separada de la corrutina. El callback de red debe anularse, de lo contrario permanecerá en el sistema incluso después de que la Activity sea destruida.
Un Fragment limpia correctamente las referencias a View en onDestroyView, evitando fugas de memoria debido a closures.
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 destruido")
}
}
En onDestroyView, las referencias a View se establecen a null — esto evita fugas de memoria si un closure en imageLoader mantiene una referencia a avatarView. El Fragment en sí y su ViewModel permanecen vivos hasta onDestroy. imageLoader.cancel() cancela la carga si el Fragment sale de la pantalla.
Usar isFinishing() permite distinguir si la Activity finaliza por comando del usuario o para recreación.
class AnalyticsActivity : AppCompatActivity() {
private val analytics = Analytics()
override fun onDestroy() {
if (isFinishing) {
Log.d("AnalyticsActivity", "Activity finalizando con finish() — enviando analítica")
analytics.sendSessionEnd()
} else {
Log.d("AnalyticsActivity", "Activity siendo recreada (rotación/configuración) — no enviando analítica")
}
super.onDestroy()
}
}
Verificar isFinishing() es un patrón importante para análisis, registro y limpieza de datos de sesión. Durante la rotación, no se deben enviar eventos de fin de sesión — el usuario todavía está trabajando con la aplicación. Según Google Analytics, la verificación incorrecta de isFinishing() es la causa del 40% de eventos de sesión falsos.
Preguntas Frecuentes
Sí, puede — durante la muerte del proceso por el sistema, Forzar Detención por el usuario o terminación anormal. Según Google, aproximadamente el 5–8% de las terminaciones de Activity ocurren sin que se llame a onDestroy. Los desarrolladores no deben confiar en onDestroy para guardar datos críticos — usa onPause u onSaveInstanceState.
finish() — una llamada que inicia la destrucción de la Activity. onDestroy — un callback que se llama durante la ejecución de finish(). finish() es necesario para que se llame a onDestroy durante la terminación normal. finish() puede ser llamado por el sistema o el desarrollador, onDestroy es solo un callback del sistema.
Sí, absolutamente tanto en Activity como en Fragment. super.onDestroy() garantiza la limpieza adecuada de ChildFragmentManager, LoaderManager y otros componentes del sistema. Omitir super.onDestroy() provoca fugas de memoria y errores con la restauración de fragments.
onCleared() se llama después de onDestroy de Activity o Fragment, cuando el ViewModel ya no es necesario. Durante la rotación de pantalla, onCleared() no se llama — ViewModel sobrevive a onDestroy. Orden: onDestroy de Activity/Fragment → (ViewModelStore se limpia) → onCleared().
Técnicamente sí, pero no se recomienda. La Activity se destruye inmediatamente después de onDestroy y el Service iniciado queda sin control. Para tareas en segundo plano, usa WorkManager con un retraso: WorkManager garantiza la ejecución incluso después de que la Activity finalice y sobrevive a la muerte del proceso.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también