onDestroy: qué es, finalización del trabajo de Activity en Android

Autor: IT Sectr Publicado: 2026-03-04 Tiempo de lectura: 8 min

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 — la última llamada antes de destruir una Activity o Fragment, destinada a la limpieza final de recursos.
  • La llamada a onDestroy no está garantizada durante la muerte del proceso por el sistema — no confíes en ella para guardar datos críticos.
  • En onDestroy debes cancelar tareas en segundo plano, cerrar sockets y bases de datos, y limpiar el ViewModelStore.
  • Diferencia con onStop: onStop — pérdida de visibilidad (Activity sigue en memoria), onDestroy — destrucción completa.
  • isFinishing() en onDestroy muestra si la Activity finaliza por comando del usuario (finish()) o por decisión del sistema.

onDestroy: ¿qué es en Android?

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:

  • Llamada explícita a finish() — el usuario presionó “Atrás” o el desarrollador llamó a finishActivity().
  • Rotación de pantalla — la Activity se destruye y se recrea con una nueva configuración.
  • Cambio de configuración — teclado, cambio de idioma, cambio de tamaño de pantalla (multi-ventana).
  • Decisión del sistema — Android elimina la Activity para liberar recursos (pero puede que no se llame 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).

Cuándo se llama a onDestroy — y cuándo no se llama

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:

  • El usuario presiona el botón “Atrás” — Activity.finish() → onPause → onStop → onDestroy.
  • Rotación de pantalla — la Activity se destruye (onPause → onStop → onDestroy), luego se recrea.
  • Cambio de configuración — ajuste del sistema que requiere recreación de la Activity.
  • Llamada a finishAffinity() — finaliza todas las Activities en la pila.
  • Eliminación de un Fragment del FragmentManager — el Fragment recibe onPause → onStop → onDestroyView → onDestroy → onDetach.

Cuándo NO se llama a onDestroy:

  • Muerte del proceso por el sistema — Android elimina todo el proceso de la aplicación cuando falta memoria. La Activity no recibe onDestroy porque el proceso termina a nivel del kernel de Linux.
  • Terminación anormal — una excepción no capturada en el hilo principal elimina la aplicación sin llamar a onDestroy.
  • Forzar detención — el usuario detiene forzosamente la aplicación en los ajustes.

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 en Activity y Fragment: similitudes y diferencias

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

ComponenteMétodos de destrucciónOrdenViewModel sobrevive
ActivityonDestroyonPause → onStop → onDestroyNo (solo si ViewModelStore no se guarda)
FragmentonDestroyView, onDestroy, onDetachonPause → onStop → onDestroyView → onDestroy → onDetachSí, 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.

Qué hacer en onDestroy: lista de verificación de limpieza

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:

  • Cancelar corrutinas y Flow — cancela los jobs que no están vinculados a viewModelScope. viewModelScope se cancela automáticamente, pero lifecycleScope está vinculado al ciclo de vida de la Activity.
  • Cerrar sockets y canales — WebSocket (OkHttp), BluetoothSocket, ServerSocket. Mantenerlos abiertos después de la destrucción es una fuga de recursos del sistema.
  • Cerrar archivos y flujos — FileInputStream, FileOutputStream, Cursor. Un Cursor puede causar ANR en ContentProvider si no se cierra.
  • Cancelar suscripción de ContentObserver — si la Activity está observando cambios de contenido (contactos, biblioteca multimedia).
  • Anular registro de BroadcastReceiver — los receivers registrados dinámicamente deben cancelarse.
  • Cerrar base de datos — Room cierra la conexión automáticamente cuando se destruye la Application, pero SQLiteDatabase directo requiere close() manual.

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.

onDestroy y ViewModel: trabajo conjunto

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:

  • Activity: onPause → onStop → onDestroy (Activity destruida).
  • ViewModel: NO destruido — el ViewModelStore se guarda y se pasa a la nueva Activity.
  • Nueva Activity: onCreate → onStart → onResume, recibe el mismo ViewModel.

Durante finish() (el usuario presionó “Atrás”):

  • Activity: onPause → onStop → onDestroy.
  • ViewModel: onCleared() — se llama después de onDestroy de la Activity.
  • Todas las corrutinas de viewModelScope se cancelan automáticamente.

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.

Ejemplos de código con onDestroy en Kotlin

Ejemplo 1: onDestroy Activity con cancelación de corrutina de lifecycleScope

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.

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

Ejemplo 2: onDestroy Fragment con limpieza de referencias a View

Un Fragment limpia correctamente las referencias a View en onDestroyView, evitando fugas de memoria debido a closures.

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

Ejemplo 3: Verificación de isFinishing en onDestroy

Usar isFinishing() permite distinguir si la Activity finaliza por comando del usuario o para recreación.

kotlin
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

¿Puede onDestroy no ser llamado?

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.

¿Cuál es la diferencia entre onDestroy y finish()?

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.

¿Necesito llamar a super.onDestroy() en Fragment?

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.

¿Cuándo se llama a onCleared() en ViewModel respecto a onDestroy?

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

¿Puedo iniciar un Service desde onDestroy?

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

  • onDestroy — el callback final del ciclo de vida de Activity y Fragment, llamado antes de la destrucción completa del componente.
  • La llamada a onDestroy no está garantizada durante la muerte del proceso — aproximadamente el 5–8% de las terminaciones ocurren sin ella.
  • En onDestroy debes liberar: callbacks de red, sockets, flujos de archivos, BroadcastReceiver, ContentObserver.
  • ViewModel.onCleared() se llama después de onDestroy de la Activity — viewModelScope se cancela automáticamente.
  • onDestroyView en Fragment (separado de onDestroy) — el lugar adecuado para anular las referencias a View.
  • Verificar isFinishing() en onDestroy permite distinguir la terminación por finish() de la recreación por cambios de configuración.
  • No confíes en onDestroy para guardar datos — usa onPause u onSaveInstanceState.

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.

Discutir el proyecto

Lea también