Ciclo de vida de la actividad

A medida que un usuario navega por tu app, sale de ella y vuelve a ingresar, las instancias de Activity de tu app pasan por diferentes estados en su ciclo de vida. La clase Activity proporciona una serie de devoluciones de llamada que permiten que la actividad sepa cuándo cambia un estado o que el sistema está creando, deteniendo o reanudando una actividad, o bien destruyendo el proceso en el que reside la actividad.

Dentro de los métodos de devolución de llamada de ciclo de vida, puedes declarar cómo se comporta tu actividad cuando el usuario sale de ella y vuelve a ingresar. Por ejemplo, si estás creando un reproductor de video de transmisión, puedes pausar el video y finalizar la conexión de red cuando el usuario cambia a otra app. Cuando el usuario regresa, puedes volver a conectarte a la red y permitir que el usuario reanude el video desde el mismo punto.

Cada devolución de llamada te permite realizar un trabajo específico que sea adecuado para un cambio de estado determinado. Realizar el trabajo correcto en el momento adecuado y controlar las transiciones de forma apropiada hace que tu app sea más sólida y tenga un mejor rendimiento. Por ejemplo, una buena implementación de las devoluciones de llamada de ciclo de vida puede ayudar a que tu app evite lo siguiente:

  • Fallas si el usuario recibe una llamada telefónica o cambia a otra app mientras usa la tuya
  • Consumir recursos valiosos del sistema cuando el usuario no lo está usando de forma activa
  • Perder el progreso del usuario si este sale de la app y regresa más tarde
  • La app falla o se pierde el progreso del usuario cuando la pantalla rota entre la orientación horizontal y vertical.

En este documento, se explica en detalle el ciclo de vida de las actividades. El documento comienza con una descripción del paradigma del ciclo de vida. A continuación, se explica cada una de las devoluciones de llamada: qué sucede internamente mientras se ejecutan y qué debes implementar durante ellas.

Luego, se presenta brevemente la relación entre el estado de la actividad y la vulnerabilidad de un proceso para que el sistema lo finalice. Por último, se analizan varios temas relacionados con las transiciones entre los estados de las actividades.

Para obtener información sobre cómo controlar los ciclos de vida, incluida orientación sobre las prácticas recomendadas, consulta Ciclo de vida en Jetpack Compose y Cómo guardar estados de IU. Para aprender a diseñar una app sólida y de calidad de producción con actividades en combinación con componentes de la arquitectura, consulta la Guía de arquitectura de apps.

Conceptos de los ciclos de vida de las actividades

Para navegar por las transiciones entre las etapas del ciclo de vida de la actividad, la clase Activity proporciona un conjunto principal de seis devoluciones de llamada: onCreate, onStart, onResume, onPause, onStop y onDestroy. El sistema invoca cada una de estas devoluciones de llamada a medida que la actividad ingresa a un estado nuevo.

En la Figura 1, se presenta una representación visual de este paradigma.

Figura 1: Ilustración simplificada del ciclo de vida de la actividad

A medida que el usuario comienza a salir de la actividad, el sistema llama a métodos para desmantelarla. En algunos casos, la actividad solo se desmantela parcialmente y aún reside en la memoria, como cuando el usuario cambia a otra app. En estos casos, la actividad aún puede volver al primer plano.

Si el usuario regresa a la actividad, esta se reanudará desde donde la dejó. Con algunas excepciones, las apps tienen restringido el inicio de actividades cuando se ejecutan en segundo plano.

La probabilidad de que el sistema finalice un proceso determinado, junto con las actividades que contiene, depende del estado de la actividad en ese momento. Para obtener más información sobre la relación entre el estado y la vulnerabilidad a la expulsión, consulta la sección sobre el estado de la actividad y la expulsión de la memoria.

Según la complejidad de tu actividad, es probable que no necesites implementar todos los métodos del ciclo de vida. Sin embargo, es importante que comprendas cada uno de ellos y que implementes los que hagan que tu app se comporte de la manera que esperan los usuarios.

Compose y el ciclo de vida

En Compose, evita colocar la lógica empresarial o la configuración manual del observador directamente en las devoluciones de llamada de la actividad, como onStart o onResume. En su lugar, usa efectos optimizados para el ciclo de vida y observadores optimizados para el estado que se alineen automáticamente con la presencia de la IU en la pantalla.

  • Recopilación optimizada para ciclos de vida: Usa collectAsStateWithLifecycle para consumir flujos de tu ViewModel. Esta API comienza a recopilar datos automáticamente cuando la IU ingresa al estado Started y se detiene cuando pasa a segundo plano, lo que evita el consumo innecesario de recursos. Después de recopilar el flujo como estado, puedes usar LifecycleEffects para ejecutar código cuando se produce un evento de ciclo de vida.
  • Flujo de lógica: Con estas APIs, la IU reacciona al estado del ciclo de vida de forma natural a través del árbol de composición, lo que garantiza que la lógica empresarial solo se ejecute cuando el usuario interactúa de forma activa con el componente.

Para obtener más información sobre Compose y el ciclo de vida, consulta Ciclo de vida en Jetpack Compose.

Devoluciones de llamada del ciclo de vida

En esta sección, se proporciona información conceptual y de implementación sobre los métodos de devolución de llamada que se usan durante el ciclo de vida de la actividad.

Algunas acciones pertenecen a los métodos del ciclo de vida de la actividad. Sin embargo, coloca el código que implementa las acciones de un componente dependiente en el componente, en lugar del método del ciclo de vida de la actividad. Para lograrlo, debes hacer que el componente dependiente tenga en cuenta el ciclo de vida. Para aprender a hacer que tus componentes dependientes estén optimizados para ciclos de vida, consulta Ciclo de vida en Jetpack Compose.

onCreate

Debes implementar esta devolución de llamada, que se activa cuando el sistema crea la actividad por primera vez. Cuando se crea la actividad, esta entra en el estado Created. En el método onCreate, implementa la lógica básica de inicio de la aplicación que se ejecuta solo una vez durante todo el ciclo de vida de la actividad.

Por ejemplo, tu implementación de onCreate podría vincular datos a listas, asociar la actividad con un ViewModel y crear una instancia de algunas variables de alcance de clase. Este método recibe el parámetro savedInstanceState, que es un objeto Bundle que contiene el estado guardado anteriormente de la actividad. Si la actividad nunca existió, el valor del objeto Bundle es nulo.

Si tienes un componente optimizado para ciclos de vida que está conectado al ciclo de vida de tu actividad, este recibe el evento ON_CREATE. Se llama al método anotado con @OnLifecycleEvent para que tu componente optimizado para ciclos de vida pueda ejecutar cualquier código de configuración que necesite para el estado creado.

En el siguiente ejemplo, se muestra cómo integrar un elemento de componibilidad Text en una actividad mínima:

class ExampleActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent { // In here, we can call composables!
            MaterialTheme {
                Greeting(name = "compose")
            }
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

Tu actividad no permanece en el estado Created. Después de que finaliza la ejecución del método onCreate, la actividad ingresa al estado Iniciada y el sistema llama a los métodos onStart y onResume en una sucesión rápida.

onStart

Cuando la actividad entra en el estado Iniciada, el sistema invoca onStart. Esta llamada hace que la actividad sea visible para el usuario, mientras la app se prepara para que la actividad pase a primer plano y se vuelva interactiva. Por ejemplo, en este método, se inicializa el código que mantiene la IU.

Cuando la actividad pasa al estado Iniciada, cualquier componente optimizado para ciclos de vida vinculado al ciclo de vida de la actividad recibe el evento ON_START.

El método onStart se completa con rapidez y, al igual que con el estado Created, la actividad no permanece en el estado Started. Una vez que finaliza esta devolución de llamada, la actividad ingresa al estado Reanudada y el sistema invoca el método onResume.

onResume

Cuando la actividad ingresa al estado Reanudada, pasa al primer plano y el sistema invoca la devolución de llamada onResume. Este es el estado en el que la app interactúa con el usuario. La app permanece en este estado hasta que ocurre algo que le quita el foco, como cuando el dispositivo recibe una llamada telefónica, el usuario navega a otra actividad o se apaga la pantalla del dispositivo.

Cuando la actividad pasa al estado Resumed, cualquier componente optimizado para ciclos de vida vinculado al ciclo de vida de la actividad recibe el evento ON_RESUME. Aquí es donde los componentes del ciclo de vida pueden habilitar cualquier funcionalidad que deba ejecutarse mientras el componente esté visible y en primer plano, como iniciar una vista previa de la cámara.

Cuando se produce un evento de interrupción, la actividad ingresa al estado Paused y el sistema invoca la devolución de llamada onPause.

Si la actividad vuelve al estado Resumed desde el estado Paused, el sistema vuelve a llamar al método onResume. Por este motivo, implementa onResume para inicializar los componentes que liberas durante onPause y realizar cualquier otra inicialización que deba ocurrir cada vez que la actividad ingrese al estado Reanudada.

A continuación, se muestra un ejemplo de un componente que tiene en cuenta el ciclo de vida y accede a la cámara cuando recibe el evento ON_RESUME:

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun initializeCamera() {
        if (camera == null) {
            getCamera()
        }
    }
    ...
}

El código anterior inicializa la cámara una vez que LifecycleObserver recibe el evento ON_RESUME. Sin embargo, en el modo multiventana, tu actividad podría ser completamente visible incluso cuando esté en el estado Pausado. Por ejemplo, cuando la app está en modo multiventana y el usuario presiona la ventana que no contiene tu actividad, esta pasa al estado Pausada.

Si quieres que la cámara esté activa solo cuando se reanude la app (visible y activa en primer plano), inicializa la cámara después del evento ON_RESUME que se mostró anteriormente. Si quieres mantener la cámara activa mientras la actividad está en pausa, pero visible, como en el modo multiventana, inicializa la cámara después del evento ON_START.

Sin embargo, tener la cámara activa mientras tu actividad está en pausa podría denegar el acceso a la cámara a otra app reanudada en el modo multiventana. A veces, es necesario mantener la cámara activa mientras la actividad está en pausa, pero, si lo haces, es posible que se degrade la experiencia general del usuario.

Por este motivo, piensa detenidamente en qué parte del ciclo de vida es más apropiado tomar el control de los recursos compartidos del sistema en el contexto del modo multiventana. Para obtener más información sobre cómo admitir el modo multiventana, consulta Cómo admitir el modo multiventana.

Independientemente del evento de compilación que elijas para realizar una operación de inicialización, asegúrate de usar el evento de ciclo de vida correspondiente para liberar el recurso. Si inicializas algo después del evento ON_START, libéralo o finalízalo después del evento ON_STOP. Si inicializas después del evento ON_RESUME, libera después del evento ON_PAUSE.

En el fragmento de código anterior, se coloca el código de inicialización de la cámara en un componente que tiene en cuenta el ciclo de vida. En su lugar, puedes colocar este código directamente en las devoluciones de llamada del ciclo de vida de la actividad, como onStart y onStop, pero no lo recomendamos. Agregar esta lógica a un componente independiente que tiene en cuenta el ciclo de vida te permite reutilizar el componente en varias actividades sin tener que duplicar el código. Para aprender a crear un componente optimizado para ciclos de vida, consulta Ciclo de vida en Jetpack Compose.

onPause

El sistema llama a este método como primera indicación de que el usuario abandona tu actividad, aunque no siempre significa que se esté destruyendo la actividad. Indica que la actividad ya no está en primer plano, pero sigue siendo visible si el usuario está en el modo multiventana. Existen varios motivos por los que una actividad puede ingresar a este estado:

  • Un evento que interrumpe la ejecución de la app, como se describe en la sección sobre la devolución de llamada onResume, pausa la actividad actual. Este es el caso más común.
  • En el modo multiventana, solo una app tiene el foco en un momento determinado, y el sistema pausa todas las demás.
  • La apertura de una actividad nueva y semitransparente, como un diálogo, pausa la actividad que cubre. Mientras la actividad sea parcialmente visible, pero no esté enfocada, permanecerá pausada.

Cuando una actividad pasa al estado Pausada, cualquier componente optimizado para ciclos de vida vinculado al ciclo de vida de la actividad recibe el evento ON_PAUSE. Aquí es donde los componentes del ciclo de vida pueden detener cualquier funcionalidad que no necesite ejecutarse mientras el componente no esté en primer plano, como detener una vista previa de la cámara.

Usa el método onPause para pausar o ajustar las operaciones que no pueden continuar o que podrían continuar con moderación, mientras la Activity se encuentra en estado de pausa, y que esperas reanudar en breve.

También puedes usar el método onPause para liberar recursos del sistema, controladores de sensores (como el GPS) o cualquier recurso que afecte la duración de la batería mientras la actividad está pausada y el usuario no los necesita.

Sin embargo, como se mencionó en la sección sobre onResume, es posible que una actividad pausada siga siendo completamente visible si la app está en modo multiventana. Considera usar onStop en lugar de onPause para liberar o ajustar por completo los recursos relacionados con la IU y las operaciones para admitir mejor el modo multiventana.

En el siguiente ejemplo de un LifecycleObserver que reacciona al evento ON_PAUSE, que es la contraparte del ejemplo del evento ON_RESUME anterior, se libera la cámara que se inicializa después de que se recibe el evento ON_RESUME:

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun releaseCamera() {
        camera?.release()
        camera = null
    }
    ...
}

En este ejemplo, se coloca el código de liberación de la cámara después de que el LifecycleObserver recibe el evento ON_PAUSE.

La ejecución de onPause es muy breve y no necesariamente ofrece suficiente tiempo para realizar operaciones de guardado. Por este motivo, no uses onPause para guardar datos de la aplicación o del usuario, realizar llamadas de red ni ejecutar transacciones de bases de datos. Es posible que ese trabajo no se complete antes de que se complete el método.

En su lugar, realiza operaciones de apagado de carga pesada durante onStop. Para obtener más información sobre las operaciones adecuadas que se deben realizar durante onStop, consulta la siguiente sección. Para obtener más información sobre cómo guardar datos, consulta la sección sobre cómo guardar y restablecer el estado.

La finalización del método onPause no significa que la actividad salga del estado Pausado. En cambio, la actividad permanece en este estado hasta que se reanuda o se vuelve completamente invisible para el usuario. Si la actividad se reanuda, el sistema vuelve a invocar la devolución de llamada onResume.

Si la actividad vuelve del estado Pausada al estado Reanudada, el sistema mantiene la instancia de Activity residente en la memoria y la recupera cuando el sistema invoca a onResume. En este caso, no necesitas volver a inicializar los componentes creados durante ninguno de los métodos de devolución de llamada que conducen al estado Resumed. Si la actividad se vuelve completamente invisible, el sistema llama a onStop.

onStop

Cuando la actividad ya no es visible para el usuario, ingresa al estado Detenida, y el sistema invoca la devolución de llamada onStop. Esto puede ocurrir cuando una actividad recién iniciada cubre toda la pantalla. El sistema también llama a onStop cuando la actividad termina de ejecutarse y está a punto de finalizar.

Cuando la actividad pasa al estado Detenida, cualquier componente optimizado para ciclos de vida vinculado al ciclo de vida de la actividad recibe el evento ON_STOP. Aquí es donde los componentes del ciclo de vida pueden detener cualquier funcionalidad que no necesite ejecutarse mientras el componente no sea visible en la pantalla.

En el método onStop, libera o ajusta los recursos que no se necesitan mientras la app no está visible para el usuario. Por ejemplo, tu app podría pausar las animaciones o cambiar de actualizaciones de ubicación detalladas a generales. Usar onStop en lugar de onPause significa que el trabajo relacionado con la IU continúa, incluso cuando el usuario ve tu actividad en el modo multiventana.

Además, usa onStop para realizar operaciones de cierre que consuman mucha CPU. Por ejemplo, si no encuentras un mejor momento para guardar información en una base de datos, puedes hacerlo durante onStop. En el siguiente ejemplo, se muestra una implementación de onStop que guarda el contenido de una nota de borrador en el almacenamiento persistente:

override fun onStop() {
    super.onStop()

    // Delegate the save operation to the ViewModel, which handles the
    // background thread operations (e.g., using Kotlin Coroutines and Room).
    noteViewModel.saveDraft()
}

Cuando tu actividad ingresa al estado Detenida, el objeto Activity se mantiene residente en la memoria: conserva toda la información de estado y de miembros, pero no se adjunta al administrador de ventanas. Cuando se reanuda la actividad, se recupera esta información.

Desde el estado Stopped, la actividad regresa a interactuar con el usuario o se termina de ejecutar y desaparece. Si la actividad regresa, el sistema invoca onRestart. Si el Activity termina de ejecutarse, el sistema llama a onDestroy.

onDestroy

Se llama a onDestroy antes de que se destruya la actividad. El sistema invoca esta devolución de llamada por uno de los siguientes motivos:

  1. La actividad está finalizando, ya sea porque el usuario la descartó por completo o porque se llamó a finish en la actividad.
  2. El sistema destruye temporalmente la actividad debido a un cambio de configuración, como la rotación del dispositivo o el ingreso al modo multiventana.

Cuando la actividad pasa al estado destruido, cualquier componente optimizado para ciclos de vida vinculado al ciclo de vida de la actividad recibe el evento ON_DESTROY. Aquí es donde los componentes del ciclo de vida pueden limpiar todo lo que necesiten antes de que se destruya el Activity.

En lugar de colocar lógica en tu Activity para determinar por qué se destruye, usa un objeto ViewModel que contenga los datos de vista relevantes para tu Activity. Si el Activity se vuelve a crear debido a un cambio de configuración, el ViewModel no tiene que hacer nada, ya que se conserva y se asigna a la siguiente instancia de Activity.

Si no se vuelve a crear el Activity, se llama al método onCleared del ViewModel, en el que se pueden limpiar los datos que se necesiten antes de que se destruya. Puedes distinguir entre estas dos situaciones con el método isFinishing.

Si la actividad está finalizando, onDestroy es la última devolución de llamada de ciclo de vida que recibe. Si se llama a onDestroy como resultado de un cambio de configuración, el sistema crea de inmediato una nueva instancia de actividad y, luego, llama a onCreate en esa instancia nueva en la configuración nueva.

La devolución de llamada onDestroy libera todos los recursos que no se liberaron en las devoluciones de llamada anteriores, como onStop.

Estado de actividad y expulsión de memoria

El sistema finaliza los procesos cuando necesita liberar RAM. La probabilidad de que el sistema finalice un proceso determinado depende del estado del proceso en ese momento. A su vez, el estado del proceso depende del estado de la actividad que se ejecuta en él. En la tabla 1, se muestran las correlaciones entre el estado del proceso, el estado de la actividad y la probabilidad de que el sistema finalice el proceso. Esta tabla solo se aplica si un proceso no ejecuta otros tipos de componentes de la aplicación.

Probabilidad de que finalice

Estado del proceso

Estado final de la actividad

Más baja

Primer plano (en foco o por estar en él)

Reanudado

Baja

Visible (sin enfoque)

Iniciada/En pausa

Alto

En segundo plano (invisible)

Detenida

Más alta

Vacío

Finalizado

Tabla 1. Relación entre el ciclo de vida del proceso y el estado de la actividad

El sistema nunca finaliza una actividad de forma directa para liberar memoria. En cambio, finaliza el proceso en el que se ejecuta la actividad, lo que destruye no solo la actividad, sino también todo lo que se ejecuta en el proceso. Para aprender a conservar y restablecer el estado de la IU de tu actividad cuando se produce el cierre del proceso iniciado por el sistema, consulta la sección sobre cómo guardar y restablecer el estado.

El usuario también puede finalizar un proceso con el Administrador de aplicaciones, en Configuración, para finalizar la app correspondiente.

Para obtener más información sobre los procesos, consulta Descripción general de los procesos y subprocesos.

Cómo guardar y restablecer el estado transitorio de la IU

El usuario espera que se conserve el estado de la IU de una actividad durante un cambio de configuración, como la rotación o el cambio al modo multiventana. Sin embargo, el sistema finaliza la actividad de forma predeterminada cuando se produce un cambio de configuración de este tipo, lo que elimina cualquier estado de la IU almacenado en la instancia de actividad.

Del mismo modo, el usuario espera que se conserve el estado de la IU si cambia temporalmente de tu app a otra y, luego, vuelve a la tuya. Sin embargo, el sistema puede destruir el proceso de tu aplicación mientras el usuario está ausente y tu actividad está detenida.

Cuando las restricciones del sistema destruyan la actividad, conserva el estado de la IU transitorio del usuario con una combinación de ViewModel (para la lógica empresarial compleja y el estado de la pantalla), la API de rememberSaveable de Jetpack Compose (para el estado de la IU liviano) o el almacenamiento local. Para obtener más información sobre las expectativas de los usuarios en comparación con el comportamiento del sistema y cómo conservar mejor los datos de estado de la IU complejos en la actividad iniciada por el sistema y el cierre del proceso, consulta Cómo guardar estados de la IU.

rememberSaveable sobrevive automáticamente a los cambios de configuración y al cierre del proceso iniciado por el sistema, ya que agrupa el estado de forma interna, lo que proporciona una experiencia fluida sin necesidad de código estándar a nivel de la actividad.

Estado de la instancia

Existen algunas situaciones en las que tu actividad se destruye debido al comportamiento normal de la app, como cuando el usuario presiona el botón Atrás o cuando tu actividad indica su propia destrucción llamando al método finish.

Cuando se destruye tu actividad porque el usuario presiona Atrás o la actividad finaliza por sí sola, el concepto de esa instancia de Activity, tanto del sistema como del usuario, desaparece para siempre. En estos casos, la expectativa del usuario coincide con el comportamiento del sistema, por lo que no tienes que realizar ningún trabajo adicional.

Sin embargo, si el sistema destruye la actividad debido a restricciones del sistema (como un cambio de configuración o presión de memoria), aunque la instancia de Activity real ya no exista, el sistema recordará que existió. Si el usuario intenta volver a la actividad, el sistema crea una instancia nueva de esa actividad con un conjunto de datos guardados que describen el estado de la actividad cuando se destruyó.

Los datos guardados que usa el sistema para restablecer el estado anterior se denominan estado de la instancia. En segundo plano, es una colección de pares clave-valor. De forma predeterminada, el sistema usa el estado de la instancia para guardar información básica sobre el diseño de la IU, como la entrada de texto del usuario o las posiciones de desplazamiento.

Puedes conectarte a este comportamiento del sistema con rememberSaveable. Si se destruye y se vuelve a crear tu instancia de actividad, se restablecerá automáticamente cualquier estado de la IU unido a rememberSaveable, sin que debas agregar código adicional a nivel de la actividad.

Sin embargo, es probable que tu actividad tenga información de estado más compleja que quieras restablecer, como datos del usuario, respuestas de red o variables de miembro que hagan un seguimiento del progreso del usuario. El mecanismo de estado de instancia (y, por extensión, rememberSaveable) no es adecuado para conservar más que una cantidad trivial de datos, ya que requiere serialización en el subproceso principal y consume memoria del proceso del sistema.

Para conservar más que una cantidad muy pequeña de datos, adopta un enfoque combinado con el almacenamiento local persistente, la clase ViewModel y la elevación de estado de Compose, como se describe en Cómo guardar estados de la IU.

Guarda el estado de la IU simple y liviano con rememberSaveable

A medida que la actividad comienza a detenerse, el sistema se prepara para guardar la información de estado en un paquete de estado de instancia. Para conectarte a este comportamiento del sistema, usa rememberSaveable directamente dentro de tus funciones de componibilidad. rememberSaveable guarda y restablece automáticamente el estado transitorio de la IU, como la entrada de texto del usuario o las posiciones de desplazamiento, durante la recreación de la actividad.

Para guardar información de estado personalizada y liviana (como el progreso de un usuario en un juego), declara tu estado con rememberSaveable. El framework de Compose controla la serialización en el paquete de estado de la instancia de forma interna:

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

Para guardar datos persistentes, como las preferencias del usuario o los datos de una base de datos, aprovecha las oportunidades adecuadas cuando tu actividad esté en primer plano. Si no surge esa oportunidad, guarda los datos persistentes durante el método onStop.

Cómo restablecer el estado de la IU de la actividad utilizando el estado de la instancia guardada

Cuando se vuelve a crear tu actividad después de que se destruyó, la restauración del estado es automática. Cuando usas rememberSaveable, no necesitas escribir ninguna lógica de restablecimiento explícita, verificar si hay paquetes nulos ni anular devoluciones de llamada de actividad. El código que inicializa y guarda tu estado también lo restablece sin problemas cuando la actividad regresa:

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

Actividades y navegación

Es probable que una app realice transiciones entre pantallas muchas veces durante su ciclo de vida, por ejemplo, cuando el usuario presiona el botón Atrás del dispositivo o selecciona un destino nuevo. Por lo general, las apps para Android modernas usan una arquitectura de actividad única. En lugar de iniciar un nuevo Activity para cada pantalla, tu app aloja un solo Activity y usa el componente Navigation para intercambiar pantallas de componibles dentro de esa actividad.

Para aprender a implementar la navegación moderna que prioriza Compose, consulta la guía de la biblioteca Navigation 3 de Jetpack Compose.

Cómo iniciar una actividad desde otra

Es posible que una actividad deba iniciar otra en algún momento. Esta necesidad surge, por ejemplo, cuando una app necesita pasar de la pantalla actual a una nueva.

Según si tu actividad desea obtener un resultado de la nueva actividad que está por iniciar, puedes iniciar la nueva actividad con el método startActivity o el método startActivityForResult. En cualquier caso, debes pasar un objeto Intent.

El objeto Intent especifica la actividad exacta que deseas iniciar o describe el tipo de acción que quieres realizar. El sistema selecciona la actividad adecuada para ti, que incluso puede ser de una aplicación diferente. Un objeto Intent también puede transportar pequeñas cantidades de datos que usará la actividad que se inicia. Para obtener más información sobre la clase Intent, consulta Intents y filtros de intents.

startActivity

Si la actividad que se acaba de iniciar no necesita devolver un resultado, la actividad actual puede iniciarla llamando al método startActivity.

Cuando trabajas en tu propia aplicación, a menudo solo necesitas iniciar una actividad conocida. Por ejemplo, en el siguiente fragmento de código, se muestra cómo iniciar una actividad llamada SignInActivity.

val context = LocalContext.current

Button(onClick = {
    val intent = Intent(context, SignInActivity::class.java)
    context.startActivity(intent)
}) {
    Text("Sign In")
}

Cómo iniciar actividades externas

Si bien la navegación interna de la app se controla con Navigation, tu Activity ocasionalmente necesitará iniciar otras actividades. Por lo general, esto sucede cuando quieres aprovechar una app externa para realizar una acción específica, como abrir un navegador web, enviar un correo electrónico o tomar una foto.

Para lograrlo, usa un objeto Intent para describir el tipo de acción que quieres realizar, y el sistema iniciará la actividad adecuada desde otra aplicación.

Por ejemplo, si quieres permitir que el usuario envíe un mensaje de correo electrónico, puedes crear el siguiente intent:

val intent = Intent(Intent.ACTION_SEND).apply {
    putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)

Si necesitas iniciar una actividad externa y obtener un resultado (como pedirle a la app de la cámara que tome una foto y devuelva la imagen), usa las APIs de resultados modernas de Activity en lugar de la devolución de llamada startActivityForResult obsoleta.

Cómo coordinar actividades

Cuando una actividad inicia otra, ambas experimentan transiciones en su ciclo de vida. La primera actividad deja de funcionar y entra en el estado Pausada o Detenida, mientras que se crea la otra actividad. En caso de que estas actividades compartan datos guardados en el disco o en otro lugar, es importante comprender que la primera actividad no se detiene por completo antes de que se cree la segunda. En cambio, el proceso de iniciar la segunda se superpone con el proceso de detener la primera.

El orden de las devoluciones de llamada de ciclo de vida está bien definido, en especial cuando las dos actividades se encuentran en el mismo proceso (es decir, en la misma app) y una inicia la otra. A continuación, se muestra el orden de las operaciones que se producen cuando la actividad A inicia la actividad B:

  1. Se ejecuta el método onPause de la actividad A.
  2. Los métodos onCreate, onStart y onResume de la actividad B se ejecutan en secuencia. Ahora, la actividad B tiene la atención del usuario.
  3. Si la actividad A ya no está visible en la pantalla, se ejecuta su método onStop.

Esta secuencia de devoluciones de llamada de ciclo de vida te permite administrar la transición de información de una actividad a otra.

Recursos adicionales

Para obtener más información sobre el ciclo de vida de la actividad, consulta los siguientes recursos adicionales:

Contenido de vistas