onPause: qué es, guardar el estado de Activity en Android

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

onPause es un método del ciclo de vida de Android que se llama cuando un Activity pierde el foco de entrada pero permanece parcialmente visible en la pantalla. El sistema llama a onPause antes de que un nuevo Activity pase al primer plano, al abrir un cuadro de diálogo, al presionar el botón de Aplicaciones Recientes o al recibir una llamada entrante. Este método es el último punto garantizado para guardar datos del usuario, ya que después de onStop y onDestroy el sistema puede terminar el proceso sin llamadas adicionales. Dentro de onPause, el desarrollador guarda borradores, pausa animaciones, libera la cámara y escribe el estado actual de la IU en SharedPreferences. Para más detalles sobre el ciclo de vida completo de Activity, lea el artículo Activity Lifecycle.

Puntos Clave

  • onPause — el Activity pierde el foco pero sigue visible; último punto garantizado para guardar datos
  • Guardar Estado — en onPause se guardan datos críticos del usuario: borradores, texto en formularios, progreso
  • Liberar Recursos — cámara, micrófono, reproductor de vídeo se liberan en onPause para transferirlos a otra aplicación
  • Límite de Tiempo — onPause debe completarse en 100 ms; superarlo provoca ANR y retrasa la transición
  • SharedPreferences.apply() — escritura asincrónica en onPause; commit() bloquea el hilo y puede causar ANR
  • onPause vs onStop — onPause cuando hay visibilidad parcial (diálogo), onStop cuando está completamente oculto (otro Activity)
  • onSaveInstanceState — se llama después de onPause para guardar el estado temporal en un Bundle

Qué es onPause en Android

onPause es el cuarto método del ciclo de vida de Activity, que se llama cuando la pantalla pierde el foco de entrada pero permanece parcialmente visible para el usuario. Es un estado de «transición» entre la aplicación activa y su ocultación. El sistema llama a onPause en los siguientes escenarios: apertura de otro Activity (una nueva pantalla cubre parcialmente la actual), aparición de un cuadro de diálogo (Dialog, PopupWindow, Snackbar no provocan onPause, pero DialogFragment sí), presión del botón de Aplicaciones Recientes, llamada entrante, presión del botón de Encendido para bloquear la pantalla.

La tarea principal de onPause es preparar la aplicación para la posibilidad de ser ocultada o destruida. Este es el último punto en el ciclo de vida donde el desarrollador puede estar seguro de que su código se ejecutará antes de que el sistema continúe con la transición a otro componente. Después de onPause, el sistema llama a onStop (si el Activity se oculta por completo), tras lo cual el proceso puede terminar en cualquier momento sin notificación adicional.

Según la documentación de Android Developers (2025), onPause debe ser lo más ligero y rápido posible. Mientras onPause no devuelva el control, el sistema no puede iniciar el siguiente Activity, lo que significa que el usuario ve un retraso en la transición de pantalla. Google recomienda completar onPause en menos de 100 milisegundos, y todas las operaciones largas (guardado en base de datos, escritura en disco) deben realizarse de forma asincrónica mediante corrutinas o apply().

onPause en Activity

En un Activity, el método onPause se llama cada vez que la pantalla deja de estar activa pero puede seguir mostrándose parcialmente. Un ejemplo típico: el usuario abre la aplicación Mapas, pulsa Compartir Ubicación, y aparece un diálogo del sistema de selección de aplicación sobre Mapas. El Activity de Mapas recibe onPause pero permanece visible debajo del diálogo. Cuando se cierra el diálogo, Mapas recibe onResume sin que se llame a onStart (la pantalla no se ocultó por completo).

kotlin
class NoteEditorActivity : AppCompatActivity() {
    private var binding: ActivityNoteEditorBinding? = null
    private val prefs by lazy {
        getSharedPreferences("note_drafts", Context.MODE_PRIVATE)
    }

    override fun onPause() {
        super.onPause()

        // Guardar borrador de nota — de forma asincrónica
        prefs.edit()
            .putString("draft_title", binding?.titleInput?.text.toString())
            .putString("draft_body", binding?.bodyInput?.text.toString())
            .putLong("draft_timestamp", System.currentTimeMillis())
            .apply()

        // Pausar vídeo
        binding?.videoPlayer?.pause()

        // Liberar recursos exclusivos
        releaseCamera()
        releaseAudioFocus()
    }

    override fun onResume() {
        super.onResume()
        // Restaurar borrador
        binding?.titleInput?.setText(prefs.getString("draft_title", ""))
        binding?.bodyInput?.setText(prefs.getString("draft_body", ""))
        acquireCamera()
        acquireAudioFocus()
    }
}

El ejemplo NoteEditorActivity demuestra el manejo correcto de onPause: guardar un borrador en SharedPreferences mediante apply(), pausar un archivo de vídeo, liberar la cámara y el foco de audio. Cada llamada es ligera y rápida, sin bloquear el hilo de la IU el tiempo suficiente para provocar ANR. Observe el orden: super.onPause() se llama en la primera línea, lo que garantiza que la lógica del sistema se ejecute incluso si se produce una excepción en el código del usuario.

Guardar Estado en onPause

onPause es el último punto donde el desarrollador puede guardar datos del usuario de forma fiable antes de que la aplicación sea ocultada o cerrada por el sistema. Después de onStop, el sistema puede terminar el proceso si falta memoria, sin llamar a onDestroy. El método onSaveInstanceState() se llama después de onPause, pero su Bundle no está diseñado para almacenamiento a largo plazo; solo vive hasta el próximo onCreate.

SharedPreferences con apply()

SharedPreferences con apply() asincrónico es la forma óptima de guardar pequeñas cantidades de datos en onPause. A diferencia de commit(), que escribe datos de forma sincrónica en disco y devuelve un booleano, apply() guarda los datos inmediatamente en memoria y programa una escritura asincrónica en disco. Esto toma menos de 1 milisegundo en el hilo de la IU, frente a 10–100 milisegundos de commit().

kotlin
override fun onPause() {
    super.onPause()

    // ❌ Malo: escritura sincrónica bloquea el hilo
    // prefs.edit().putInt("score", score).commit()

    // ✅ Bueno: escritura asincrónica
    prefs.edit().putInt("score", score).apply()

    // Para objetos complejos — almacenamiento en caché en ViewModel
    viewModel.saveState()
}

Room y Corrutinas

Para datos estructurados (SQLite a través de Room) en onPause, se usan corrutinas con lifecycleScope. ViewModelScope cancela automáticamente la corrutina cuando se destruye el ViewModel, lo que evita escrituras en una base de datos cerrada. La escritura mediante Room con corrutinas toma 5–15 milisegundos y no bloquea el hilo de la IU.

kotlin
// En ViewModel:
fun saveDraft(title: String, body: String) {
    viewModelScope.launch(Dispatchers.IO) {
        noteDao.insert(NoteDraft(title = title, body = body))
    }
}

// En Activity.onPause:
viewModel.saveDraft(
    binding?.titleInput?.text.toString(),
    binding?.bodyInput?.text.toString()
)

onPause en Fragment

onPause en Fragment se llama cuando el Fragment deja de estar activo pero puede permanecer visible. Esto ocurre cuando: un Fragment es reemplazado por otro Fragment mediante FragmentTransaction; un Fragment deja de ser la página actual en un ViewPager; el Activity que contiene el Fragment recibe onPause. La interacción entre onPause de Activity y onPause de Fragment es estrictamente jerárquica: primero recibe onPause el Activity, luego todos sus Fragments.

kotlin
class MapFragment : Fragment() {
    private var mapController: MapController? = null

    override fun onPause() {
        super.onPause()
        mapController?.stopFollowMode()
        binding?.mapContainer?.alpha = 0.7f
    }

    override fun onResume() {
        super.onResume()
        binding?.mapContainer?.alpha = 1.0f
        if (isVisible) {
            mapController?.startFollowMode()
        }
    }
}

Especificidad de trabajar con mapas en onPause: Google Maps y Yandex Maps consumen recursos significativos de GPU en modo de seguimiento activo. Al perder el foco, tiene sentido desactivar la animación del mapa y reducir la frecuencia de actualización de marcadores, y al recuperar el foco, restaurar la funcionalidad completa. Esto mejora el rendimiento y reduce el consumo de energía al cambiar entre pantallas.

onPause vs onStop: Diferencia y Escenarios

Una de las confusiones más comunes entre los desarrolladores principiantes de Android es no entender la diferencia entre onPause y onStop. Examinemos cada escenario y determinemos el método correcto.

EscenarioonPauseonStop
Apertura de un cuadro de diálogoSe llamaNo se llama
Apertura de un nuevo Activity (no transparente)Se llamaSe llama
Presión del botón InicioSe llamaSe llama
Bloqueo de pantallaSe llamaSe llama
Llamada entranteSe llamaSe llama
Activity transparente superpuestoSe llamaNo se llama
Split Screen (media pantalla)Se llamaNo se llama
PiP (Picture-in-Picture)Se llamaNo se llama

La regla principal: onPause se llama ante cualquier pérdida de foco, onStop solo cuando se pierde completamente la visibilidad. Si el Activity sigue visible (aunque sea parcialmente), onStop no se llama. Esto es críticamente importante para los modos Split Screen, PiP y Activity transparente: aquí onPause/onResume funcionan, pero onStart/onStop no.

Tiempos y Rendimiento de onPause

onPause es el método del ciclo de vida más crítico en cuanto a tiempo, porque bloquea el renderizado del siguiente Activity. El sistema espera a que finalice onPause del Activity actual antes de mostrar el nuevo. Si onPause tarda más de 100 milisegundos, el usuario nota un retraso en la transición; si tarda más de 5 segundos, el sistema muestra un ANR.

Recomendaciones de Rendimiento

La Guía de Rendimiento de Android de Google (2025) ofrece las siguientes recomendaciones para onPause: no realice solicitudes de red — deben cancelarse o trasladarse a WorkManager; no escriba archivos grandes en disco — use BufferedWriter en un hilo en segundo plano; no ejecute consultas SQL complejas — las operaciones de Room deben ser asincrónicas mediante corrutinas; evite crear nuevos objetos — la recolección de basura en onPause agrava el retraso; use apply() en lugar de commit() para SharedPreferences.

kotlin
override fun onPause() {
    super.onPause()

    // ❌ Malo: solicitud HTTP bloquea la IU
    // val response = api.syncSave(data).execute()

    // ❌ Malo: escritura sincrónica en archivo
    // FileOutputStream(file).write(data)

    // ✅ Bueno: guardado asincrónico
    lifecycleScope.launch {
        withContext(Dispatchers.IO) {
            api.saveData(data)
            fileDao.write(data)
        }
    }

    // ✅ Bueno: escritura ligera en SharedPreferences
    prefs.edit().putString("key", value).apply()
}

La creación de perfiles de onPause mediante Android Studio Profiler (traza de CPU) muestra el tiempo exacto de ejecución. Si onPause toma más de 100 ms, Profiler resalta el método en amarillo, y más de 500 ms en rojo. En proyectos comerciales de IT Sectr, usamos pruebas Macrobenchmark que verifican automáticamente el tiempo de transición entre Activities y señalan regresiones de rendimiento en el pipeline de CI.

Errores Comunes en onPause

Incluso los desarrolladores experimentados cometen errores en onPause. Examinemos cinco problemas típicos y sus soluciones.

Escritura Sincrónica en Base de Datos

Llamar a Room DAO con una consulta sincrónica (.executeAsObservable() sin corrutinas) en onPause bloquea el hilo de la IU durante 10–50 ms. Si en ese momento ocurre GC o contención de escritura, el retraso puede alcanzar 200–500 ms. Solución: use corrutinas con Dispatchers.IO o apply() para SharedPreferences.

Registrar Nuevos Listeners

onPause no es el lugar para registrar listeners. Si registra un BroadcastReceiver en onPause, permanecerá activo cuando el Activity ya no sea visible. El registro solo debe hacerse en onStart/onResume, y en onPause/onStop solo la cancelación del registro. La excepción son las API basadas en Intent que requieren registro antes de la llamada.

Ignorar Excepciones

Si se produce una excepción no controlada en onPause, el sistema no llama a onStop ni a onDestroy. El Activity se queda en un estado indefinido, y onResume al regresar puede no restaurar correctamente los recursos liberados. Solución: envuelva las operaciones críticas en try/catch con registro mediante Log.e().

Guardar Datos Redundantes

No es necesario guardar en onPause datos que se pueden restaurar fácilmente. Por ejemplo, los resultados de solicitudes a API se almacenan en caché en Room o DataStore en el momento de la obtención, no en onPause. Guarde solo lo que el usuario ingresó manualmente y no se puede restaurar automáticamente: texto en campos, elementos seleccionados, posición de desplazamiento.

Olvidar super.onPause()

super.onPause() debe llamarse, pero a diferencia de onCreate, omitirlo no provoca un fallo inmediato. El sistema «perdona» la falta de super en onPause, pero la máquina de estados interna entra en un estado incorrecto. La siguiente llamada a onResume podría no restaurar el foco de entrada, dejando el Activity “congelado.” Llame siempre a super.onPause() lo antes posible.

Preguntas Frecuentes

¿Qué sucede si se llama a finish() en onPause?

Llamar a finish() en onPause terminará el Activity inmediatamente después de regresar del método. Este es un escenario válido si se necesita cerrar la pantalla al perder el foco (por ejemplo, una pantalla de autorización al minimizar la aplicación). Sin embargo, finish() desencadena el ciclo completo de terminación: onStop onDestroy, lo que añade un retraso a la transición. Use finish() en onPause solo cuando sea realmente necesario.

¿En qué se diferencia onPause de onSaveInstanceState?

onPause es para guardar datos que deben sobrevivir a la terminación del proceso (borradores en SharedPreferences/Room). onSaveInstanceState es para guardar el estado temporal de la IU que solo se necesita hasta el próximo onCreate (posición de desplazamiento, pestaña seleccionada). El Bundle de onSaveInstanceState no se conserva cuando la aplicación se termina por completo; solo existe en memoria. Los datos de onPause se guardan en disco y sobreviven a un reinicio.

¿Se puede abrir un diálogo en onPause?

No se recomienda. Abrir un diálogo o ventana emergente en onPause provoca una WindowLeakException si el Activity ya ha finalizado. Si necesita mostrar una notificación al perder el foco, use NotificationManager (notificaciones del sistema): es seguro y esperado por el usuario. Para acciones diferidas, use AlarmManager o WorkManager.

¿Por qué onPause es un punto de guardado garantizado y onStop no?

Se garantiza que onPause se llama antes de que el Activity deje de estar activo. onStop puede no llamarse si el sistema mata el proceso para liberar memoria; en ese caso, onDestroy tampoco se llama. onPause es el único método después de onResume que siempre se llama, independientemente del motivo de la pérdida de foco. Por lo tanto, todos los datos críticos se guardan precisamente en onPause.

¿Cómo probar onPause en pruebas unitarias?

Para probar onPause se usan Robolectric o FragmentScenario de AndroidX Test. FragmentScenario.create() moveToState(State.STARTED) moveToState(State.RESUMED) moveToState(State.STARTED) llama secuencialmente a onPause. Luego se verifica que los datos se guardaron en SharedPreferences o que la cámara se liberó mediante un objeto mock. Robolectric 4.12+ admite la emulación de onPause/onResume sin un dispositivo físico.

Resumen

  • onPause — el Activity pierde el foco de entrada pero permanece parcialmente visible; último punto garantizado para guardar datos
  • Guardado — SharedPreferences.apply() o Room mediante corrutinas; commit() y operaciones sincrónicas están prohibidos
  • Liberación de Recursos — cámara, foco de audio, reproductor de vídeo se liberan en onPause para transferirlos a otra aplicación
  • Límite de 100 ms — onPause bloquea el renderizado del siguiente Activity; superar el límite provoca ANR
  • onPause vs onStop — onPause al perder el foco (visibilidad conservada), onStop al ocultarse completamente
  • Fragment.onPause — llamada jerárquica después de Activity.onPause; especificidad para mapas y ViewPager
  • Errores Comunes — escritura sincrónica, registro de listeners, ignorar try/catch, guardado redundante
  • super.onPause() — llamar lo antes posible; omitirlo no provoca fallo pero rompe la máquina de estados

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