Cuando un usuario navega por tu app, sale de ella y vuelve a entrar, las instancias de Activity
de tu app pasan por diferentes estados de su ciclo de vida.
La clase Activity
proporciona una serie de devoluciones de llamada.
que informan a la actividad cuando cambia un estado o que el
sistema crea, detiene o reanuda una actividad, o destruye
el proceso en el que reside la actividad.
Dentro de los métodos de devolución de llamada de ciclo de vida, puedes declarar el comportamiento que tendrá tu actividad cuando el usuario la abandone y la reanude. Por ejemplo, si estás crear un reproductor de video en streaming, puedes pausar el video y cancelar el conexión de red cuando el usuario cambia a otra aplicación. Cuando el usuario regresa, puedes volver a conectarte a la red y permitir que el usuario reanude el video desde mismo lugar.
Cada devolución de llamada te permite realizar un trabajo específico apropiado para un cambio de estado determinado. Hacer el trabajo preciso en el momento adecuado y administrar las transiciones correctamente hace que tu app sea más sólida y eficiente. Por ejemplo, una buena implementación de las devoluciones de llamada de ciclo de vida puede ayudar a que tu app evita lo siguiente:
- No falle si el usuario recibe una llamada telefónica o cambia a otra app mientras usa la tuya.
- No consuma recursos valiosos del sistema cuando el usuario no la use de forma activa.
- No pierda el progreso del usuario si este abandona tu app y regresa a ella posteriormente.
- No falle ni pierda el progreso del usuario cuando se gire la pantalla entre la orientación horizontal y la vertical.
En este documento, se explica en detalle el ciclo de vida de las actividades. Al principio del documento, se describe el paradigma del ciclo de vida. A continuación, se explica cada una de las devoluciones de llamada: lo que sucede internamente mientras se ejecutan y lo que se debe implementar durante ellas.
Luego, se presenta de forma breve la relación entre el estado de una actividad y la vulnerabilidad de un proceso que el sistema está por finalizar. Por último, se analizan varios temas relacionados con las transiciones estados de actividad.
Para obtener información sobre el manejo de ciclos de vida, incluida orientación sobre prácticas recomendadas, consulta Cómo manejar ciclos de vida con componentes optimizados para ciclos de vida y Cómo guardar estados de la IU Para aprender a diseñar una app sólida y de calidad de producción usando actividades combinación con componentes de la arquitectura, consulta 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
La clase Activity
proporciona un conjunto básico de seis devoluciones de llamada:
onCreate()
,
onStart()
,
onResume()
,
onPause()
,
onStop()
y
onDestroy()
El sistema invoca
cada una de estas devoluciones de llamada cuando la actividad entra en un nuevo estado.
En la figura 1, se muestra una representación visual de este paradigma.
Cuando el usuario comienza a abandonar la actividad, el sistema llama a métodos para desmantelarla. En algunos casos, la actividad solo se 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 vuelve a la actividad, se reanuda desde donde el usuario la dejó. Con algunas excepciones, las apps son restringido de iniciar actividades cuando se ejecutan en segundo plano
La probabilidad que tiene el sistema eliminar 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 vulnerabilidad a expulsión, consulta la sección sobre estado de actividad y expulsión de 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 comprenderlos mejor e implementar aquellos que hagan que tu app se comporte como esperan los usuarios.
Devoluciones de llamada del ciclo de vida
En esta sección, se brinda información conceptual y de implementación sobre los métodos de devolución de llamada utilizados durante el ciclo de vida de una actividad.
Algunas acciones pertenecen a los métodos del ciclo de vida de la actividad. Sin embargo, el código de lugar que implementa las acciones de un componente dependiente en la en lugar del método del ciclo de vida de la actividad. Para lograrlo, necesitas para que el componente dependiente priorice el ciclo de vida. Para aprender a hacer tus componentes dependientes optimizados para ciclos de vida, consulta Cómo manejar ciclos de vida con componentes optimizados para ciclos de vida
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 onCreate()
de inicio de la aplicación básica que
ocurre una sola vez en toda la vida de la actividad.
Por ejemplo, tu
la implementación de onCreate()
podría vincular datos a listas, asociar la actividad con un
ViewModel
,
y crear instancias de algunas variables de alcance de clase. Este método recibe el
parámetro savedInstanceState
, que es una Bundle
un objeto que contiene el estado guardado previamente de la actividad. Si la actividad tiene
que no existía antes, el valor del objeto Bundle
es nulo.
Si tienes un componente que prioriza el ciclo de vida y que está conectado al ciclo de vida de
tu actividad, recibe la
ON_CREATE
para cada evento. Se llama al método anotado con @OnLifecycleEvent
para que tu ciclo de vida esté optimizado
puede realizar cualquier código de configuración que necesite para el estado de creación.
El siguiente ejemplo del método onCreate()
Se muestra la configuración fundamental de la actividad, como declarar la interfaz de usuario.
(definido en un archivo de diseño XML), definir variables de miembros y configurar
parte de la IU. En este ejemplo, el archivo de diseño XML pasa el
el ID de recurso del archivo, R.layout.main_activity
, en
setContentView()
Kotlin
lateinit var textView: TextView // Some transient state for the activity instance. var gameState: String? = null override fun onCreate(savedInstanceState: Bundle?) { // Call the superclass onCreate to complete the creation of // the activity, like the view hierarchy. super.onCreate(savedInstanceState) // Recover the instance state. gameState = savedInstanceState?.getString(GAME_STATE_KEY) // Set the user interface layout for this activity. // The layout is defined in the project res/layout/main_activity.xml file. setContentView(R.layout.main_activity) // Initialize member TextView so it is available later. textView = findViewById(R.id.text_view) } // This callback is called only when there is a saved instance previously saved using // onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally // be restored here, possibly usable after onStart() has completed. // The savedInstanceState Bundle is same as the one used in onCreate(). override fun onRestoreInstanceState(savedInstanceState: Bundle?) { textView.text = savedInstanceState?.getString(TEXT_VIEW_KEY) } // Invoked when the activity might be temporarily destroyed; save the instance state here. override fun onSaveInstanceState(outState: Bundle?) { outState?.run { putString(GAME_STATE_KEY, gameState) putString(TEXT_VIEW_KEY, textView.text.toString()) } // Call superclass to save any view hierarchy. super.onSaveInstanceState(outState) }
Java
TextView textView; // Some transient state for the activity instance. String gameState; @Override public void onCreate(Bundle savedInstanceState) { // Call the superclass onCreate to complete the creation of // the activity, like the view hierarchy. super.onCreate(savedInstanceState); // Recover the instance state. if (savedInstanceState != null) { gameState = savedInstanceState.getString(GAME_STATE_KEY); } // Set the user interface layout for this activity. // The layout is defined in the project res/layout/main_activity.xml file. setContentView(R.layout.main_activity); // Initialize member TextView so it is available later. textView = (TextView) findViewById(R.id.text_view); } // This callback is called only when there is a saved instance previously saved using // onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally // be restored here, possibly usable after onStart() has completed. // The savedInstanceState Bundle is same as the one used in onCreate(). @Override public void onRestoreInstanceState(Bundle savedInstanceState) { textView.setText(savedInstanceState.getString(TEXT_VIEW_KEY)); } // Invoked when the activity might be temporarily destroyed; save the instance state here. @Override public void onSaveInstanceState(Bundle outState) { outState.putString(GAME_STATE_KEY, gameState); outState.putString(TEXT_VIEW_KEY, textView.getText()); // Call superclass to save any view hierarchy. super.onSaveInstanceState(outState); }
Como alternativa a definir el archivo en formato XML y pasarlo a setContentView()
, puedes
puedes crear objetos View
nuevos en tu código de actividad y crear un
jerarquía de vistas insertando nuevos objetos View
en una
ViewGroup
Luego, usa ese diseño pasando el
raíz ViewGroup
a setContentView()
.
Para obtener más información sobre cómo crear una interfaz de usuario, consulta el
Interfaz de usuario.
Tu actividad no permanece en la sección Creado
para cada estado. Cuando finaliza la ejecución del método onCreate()
, la actividad entra en el estado Started.
estado y el sistema llama a la onStart()
y onResume()
en una vista rápida
sucesión.
onStart()
Cuando la actividad entra en el estado Started, el sistema
Invoca onStart()
.
Esta llamada hace que la actividad sea visible para el usuario como
La app se prepara para que la actividad entre en primer plano y se vuelva interactiva.
Por ejemplo, este método es donde el código que mantiene
se inicializa la IU.
Cuando la actividad pasa al estado Started, cualquier componente que priorice el ciclo de vida vinculado
al ciclo de vida de la actividad recibe el
ON_START
.
El método onStart()
completa
rápidamente y, al igual que con el estado Created, la actividad no permanece
en el estado Iniciado. Una vez finalizada esta devolución de llamada, la actividad ingresa al
Resumed, y el sistema invoca
onResume()
.
onResume()
Cuando la actividad entra en el estado Reanudada, pasa al primer plano.
el sistema invoca el elemento onResume()
devolución de llamada. Este es el estado en el que la app interactúa con el usuario. La app permanece en este estado hasta que le ocurre algo
Alejar el foco de la app, como cuando
el dispositivo recibe una llamada telefónica,
navegar a otra actividad o apagar la pantalla del dispositivo.
Cuando la actividad pasa al estado Reanudada, cualquier componente que priorice el ciclo de vida vinculado
al ciclo de vida de la actividad recibe el
ON_RESUME
para cada evento. Aquí es donde los componentes del ciclo de vida pueden habilitar cualquier funcionalidad que necesite ejecutarse mientras el componente esté visible y en primer plano, como, por ejemplo, iniciar una vista previa de la cámara.
Cuando se produce un evento disruptivo, la actividad entra en el estado Pausado
de estado y el sistema invoca
Devolución de llamada onPause()
.
Si la actividad vuelve a
el estado Resumed del estado Pausado, el sistema llama una vez más
onResume()
. Por este motivo, implementa
onResume()
para inicializar los componentes que lanzas durante
onPause()
y para realizar cualquier otra
inicializaciones que deben ocurrir cada vez que la actividad ingresa al modo de reanudación
para cada estado.
Este es un ejemplo de un componente optimizado para ciclos de vida que accede a la cámara cuando
el componente recibe el evento ON_RESUME
:
Kotlin
class CameraComponent : LifecycleObserver { ... @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun initializeCamera() { if (camera == null) { getCamera() } } ... }
Java
public class CameraComponent implements LifecycleObserver { ... @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) public void 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
puede ser completamente visible
incluso cuando se encuentre en el estado En pausa. Por ejemplo, cuando
la aplicación está en el modo multiventana y el usuario presiona la ventana que no
contienen tu actividad, esta pasa al estado Detenida.
Si
quieres que la cámara se active solo cuando se reanude la app (visible
y activa en primer plano), luego inicializa la cámara después del
ON_RESUME
evento
como se demostró anteriormente. Si quieres mantener la cámara activa mientras se realiza la actividad
Esté detenido, pero visible, como en el modo multiventana, y luego
inicializa la cámara después del evento ON_START
.
Sin embargo, tener la cámara activo mientras tu actividad está En pausa puede denegar el acceso a la cámara a otra Se reanudó la app en el modo multiventana. A veces, es necesario mantener la cámara activa mientras tu actividad está En pausa, pero, en realidad, podría degradar la experiencia general del usuario si lo haces.
Por este motivo, piensa detenidamente en qué parte del es más apropiado tomar el control de los recursos compartidos del sistema el contexto del modo multiventana. Para obtener más información sobre la compatibilidad con el modo multiventana consulta Compatibilidad con el modo multiventana.
Independientemente del evento en el que decidas realizar una operación de inicialización, asegúrate de utilizar el evento de ciclo de vida correspondiente para liberar el recurso. Si inicializas algo después de
el evento ON_START
, liberarlo o finalizarlo después de
ON_STOP
evento. Si
inicializa después del evento ON_RESUME
, suéltala después del
ON_PAUSE
evento.
El fragmento de código anterior coloca el código de inicialización de la cámara en un
que prioriza el ciclo de vida. En su lugar, puedes colocar el código directamente en la actividad
devoluciones de llamada de ciclo de vida, como onStart()
y
onStop()
, pero no recomendamos esta opción. Agregar esta lógica
en un componente independiente que prioriza
el ciclo de vida permite reutilizar el componente
en múltiples actividades sin tener que duplicar el código. Para aprender a crear un componente que priorice el ciclo de vida, consulta
Cómo manejar ciclos de vida con componentes optimizados para ciclos de vida
onPause()
El sistema llama a este método como la primera indicación de que el usuario se va tu actividad, aunque no siempre significa que la actividad se esté destruyendo. Indica que la actividad ya no está en primer plano, pero está seguirá siendo visible si el usuario está en el modo multiventana. Hay varias razones por las que una actividad puede ingresar 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 está enfocada. en cualquier momento, y el sistema pausará todas las demás.
- La apertura de una nueva actividad semitransparente, como un diálogo. pausa la actividad que abarca. Siempre y cuando la actividad es parcialmente visible, pero no está en foco, permanece pausada.
Cuando una actividad pasa al estado Detenida, cualquier componente que priorice el ciclo de vida vinculado
al ciclo de vida de la actividad recibe el
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 Activity
se encuentra en el estado Detenida y que
esperamos reanudar pronto.
También puedes usar el método onPause()
para
liberar recursos del sistema, controladores de sensores (como GPS) o cualquier recurso que
afectar la duración de la batería mientras la actividad esté en el estado Pausada y el usuario no
en tu despensa hasta que los necesites.
Sin embargo, como se mencionó en la sección sobre onResume()
, un elemento
es posible que la actividad aún sea completamente visible si la app está en el modo multiventana.
Considera usar onStop()
en lugar de onPause()
para liberar o ajustar por completo
Recursos y operaciones relacionados con la IU para admitir mejor el modo multiventana
El siguiente ejemplo de un LifecycleObserver
reaccionar al evento ON_PAUSE
es la contraparte de la anterior
Ejemplo de evento ON_RESUME
y suelta la cámara que se inicializa después
se recibe el evento ON_RESUME
:
Kotlin
class CameraComponent : LifecycleObserver { ... @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) fun releaseCamera() { camera?.release() camera = null } ... }
Java
public class JavaCameraComponent implements LifecycleObserver { ... @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) public void releaseCamera() { if (camera != null) { camera.release(); camera = null; } } ... }
En este ejemplo, se coloca el código de liberación de la cámara después del
LifecycleObserver
recibe el evento ON_PAUSE
.
La ejecución de onPause()
es muy breve y
no ofrece necesariamente el tiempo suficiente
para realizar operaciones de guardado. Para este
motivo, no uses onPause()
para guardar la aplicación o el usuario
realizar llamadas de red o ejecutar transacciones de bases de datos. Es posible que ese trabajo no
complete antes de que lo haga el método.
En su lugar, realiza operaciones de apagado de cargas pesadas durante
onStop()
Más información
sobre las operaciones adecuadas para realizar
onStop()
, consulta la siguiente sección. Para obtener más información sobre cómo guardar
de 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 abandone el estado Paused. Más bien, la actividad
permanece en este estado hasta que se reanuda la actividad o se vuelve
invisible para el usuario. Si se reanuda la actividad, el sistema volverá a invocar la devolución de llamada onResume()
.
Si el botón
activa regresa del estado Detenida al estado Reanudada, el sistema mantiene
la instancia Activity
residente en la memoria, lo que recuperará
esa instancia cuando el sistema invoca a onResume()
.
En este caso, no necesitas reinicializar los componentes creados durante ninguna de las
métodos de devolución de llamada que llevan al estado Resumed. Si la actividad pasa a ser
completamente invisible, el sistema llama
onStop()
onStop()
Cuando tu actividad ya no es visible para el usuario, ingresa el
Stopped, y el sistema invoca
Devolución de llamada onStop()
. Esto puede ocurrir cuando una actividad recién lanzada cubre toda la pantalla. El
El sistema también llama a onStop()
.
Cuando la actividad termina de ejecutarse y está por finalizar.
Cuando la actividad pasa al estado Detenida, cualquier componente que priorice el ciclo de vida vinculado
al ciclo de vida de la actividad recibe el
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()
, suelta o ajusta
recursos que no son necesarios mientras la aplicación no es visible para el usuario. Por ejemplo, tu app podría pausar animaciones o cambiar de actualizaciones de ubicación detalladas a más generales. Usando
onStop()
en lugar de onPause()
significa que el trabajo relacionado con la IU continúa, incluso cuando el usuario visualiza tu actividad en el modo multiventana.
.
Además, usa onStop()
.
para realizar operaciones de apagado
con un uso relativamente intensivo de la CPU. Por ejemplo,
un mejor momento para guardar
información en una base de datos
puedes hacerlo durante onStop()
. Por ejemplo, a continuación, se muestra una implementación de onStop()
que guarda los contenidos del borrador de una nota en el almacenamiento persistente:
Kotlin
override fun onStop() { // Call the superclass method first. super.onStop() // Save the note's current draft, because the activity is stopping // and we want to be sure the current note progress isn't lost. val values = ContentValues().apply { put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText()) put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle()) } // Do this update in background on an AsyncQueryHandler or equivalent. asyncQueryHandler.startUpdate( token, // int token to correlate calls null, // cookie, not used here uri, // The URI for the note to update. values, // The map of column names and new values to apply to them. null, // No SELECT criteria are used. null // No WHERE columns are used. ) }
Java
@Override protected void onStop() { // Call the superclass method first. super.onStop(); // Save the note's current draft, because the activity is stopping // and we want to be sure the current note progress isn't lost. ContentValues values = new ContentValues(); values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText()); values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle()); // Do this update in background on an AsyncQueryHandler or equivalent. asyncQueryHandler.startUpdate ( mToken, // int token to correlate calls null, // cookie, not used here uri, // The URI for the note to update. values, // The map of column names and new values to apply to them. null, // No SELECT criteria are used. null // No WHERE columns are used. ); }
En el ejemplo de código anterior, se usa directamente SQLite. Sin embargo, recomendamos usar Room una biblioteca de persistencia que proporciona una capa de abstracción sobre SQLite. Para aprender más información sobre los beneficios de usar Room y cómo implementarlo en tu app consulta la Biblioteca de persistencias Room .
Cuando tu actividad entra en el estado Detenida, la Activity
se mantiene residente en la memoria: mantiene todos los estados y
información, pero no está adjunta al administrador de ventanas. Cuando la actividad
currículum, recuerda esta información.
No es necesario
reinicializar los componentes creados durante cualquiera de los métodos de devolución de llamada
lo que lleva al estado Resumed. El sistema también hace un seguimiento
estado para cada objeto View
en el diseño, así que si el
usuario ingresa texto en un widget EditText
, que
el contenido se retendrá para que no tengas que guardarlo ni restablecerlo.
Nota: Una vez que se detiene la actividad, el sistema puede finalizar el proceso que la contiene si necesita recuperar memoria.
Incluso si el sistema destruye el proceso mientras la actividad
se detiene, el sistema aún conserva el estado de View
objetos, como texto en un widget EditText
, en una
Bundle
, un BLOB de pares clave-valor, y los restablece.
si el usuario regresa a la actividad. Para
más información sobre cómo restablecer una actividad a la que regresa un usuario, consulta la
Sección sobre cómo guardar y restablecer el estado.
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 a onRestart()
.
Si se terminó de ejecutar Activity
, el sistema llamará a onDestroy()
.
onDestroy()
Se llama a onDestroy()
antes de que finalice la actividad. El sistema invoca esta devolución de llamada por uno de estos dos motivos:
-
La actividad está terminando debido a que el usuario descarta por completo
o debido a
finish()
está llamado a la actividad. - El sistema está finalizando temporalmente la actividad debido a una configuración cambios, como la rotación del dispositivo o el ingreso al modo multiventana.
Cuando la actividad pasa al estado Destroyed, cualquier componente que priorice el ciclo de vida vinculado
al ciclo de vida de la actividad recibe el
ON_DESTROY
. Aquí es donde
los componentes del ciclo de vida pueden
limpiar todo lo que necesiten antes de
Se destruye Activity
.
En lugar de poner lógica en tu Activity
para determinar por qué se destruye,
usa un objeto ViewModel
para que contenga la
datos de vista relevantes para tu Activity
. Si se vuelve a crear Activity
Debido a un cambio de configuración, el ViewModel
no tiene que hacer nada, ya que
se conserva y se entrega a la siguiente instancia de Activity
.
Si no se vuelve a crear Activity
, entonces ViewModel
tiene lo siguiente:
onCleared()
, donde
puede limpiar los datos que necesite antes de que los destruya. Puedes distinguir entre estos dos escenarios con el
isFinishing()
.
Si la actividad está terminando, onDestroy()
es la devolución de llamada del ciclo de vida final que
que recibe la actividad. Si se llama a onDestroy()
como resultado de una configuración
un cambio, el sistema crea inmediatamente una nueva instancia de actividad y, luego, llama
onCreate()
en la instancia nueva en la nueva configuración.
La devolución de llamada onDestroy()
libera todos los recursos que no lanzó antes.
devoluciones de llamada, como onStop()
.
Estado de actividad y expulsión de memoria
El sistema finaliza los procesos cuando necesita liberar RAM. La probabilidad del sistema finalizar un proceso determinado depende del estado del proceso en ese momento. El estado del proceso, a su vez, depende del estado de la actividad que se ejecuta en el proceso. La tabla 1 muestra las correlaciones entre el estado del proceso, la actividad el estado actual 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 de la actividad final |
---|---|---|
Muy bajo | Primer plano (en foco o por estar en él) | Reanudado |
Bajo | Visible (sin enfoque) | Iniciada/detenida |
Alto | Fondo (invisible) | Detenido |
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. Por el contrario, finaliza el proceso en el que se ejecuta la actividad y destruye no solo la actividad pero también todo lo demás que se ejecuta en el proceso. Para aprender a preservar y restablece el estado de la IU de tu actividad cuando finaliza el proceso iniciado por el sistema Consulta la sección sobre guardar y restablecer el estado.
El usuario también puede finalizar un proceso utilizando el Administrador de aplicaciones, en Configuración, finalizar la app correspondiente.
Para obtener más información sobre los procesos, consulta Procesos y subprocesos descripción general.
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, un usuario espera que el estado de la IU siga siendo el mismo si cambia temporalmente de tu app a una diferente y, luego, regresa a tu app. Sin embargo, el sistema puede destruir el proceso de tu aplicación mientras la el usuario está ausente y tu actividad se detiene.
Cuando las restricciones del sistema destruyen la actividad, se preserva el
el estado transitorio de la IU del usuario a través de una combinación
ViewModel
:
onSaveInstanceState()
,
o almacenamiento local. Para obtener más información sobre las expectativas de los usuarios en comparación con el sistema
el comportamiento del usuario y cómo preservar mejor los datos complejos del estado de la IU en toda
actividad iniciada por el sistema y cierre del proceso, consulta
Cómo guardar estados de la IU
En esta sección, se describe el estado de la instancia y cómo implementar el
onSaveInstance()
, que es una devolución de llamada en la actividad en sí. Si el
Los datos de la IU son ligeros, puedes usar solo onSaveInstance()
para conservar la IU
en los cambios de configuración y el cierre de procesos iniciados por el sistema.
Sin embargo, como onSaveInstance()
genera costos de serialización/deserialización, en
la mayoría de los casos, se usan ViewModel
y onSaveInstance()
, ya que
se describen en
Cómo guardar estados de la IU
Nota: Para obtener más información sobre los cambios de configuración, cómo restringir el objeto Activity recreación si es necesario y cómo reaccionar a esos cambios de configuración desde el de View y Jetpack Compose, consulta el Página para administrar los cambios en la configuración
Estado de la instancia
Existen algunas situaciones en las que finaliza tu actividad debido al comportamiento normal de la app, por ejemplo, cuando el usuario presiona el botón Atrás o tu actividad indica su propia finalización llamando al método finish()
.
Cuando se destruye tu actividad porque el usuario presiona Atrás
o la actividad se termina sola, tanto para el concepto de sistema como para el usuario
esa instancia Activity
desapareció para siempre. En estas
las expectativas del usuario coinciden con el comportamiento del sistema, y no
si no tienes trabajo extra que hacer.
Sin embargo, si el sistema finaliza la actividad debido a restricciones del sistema (como
un cambio de configuración o presión de la memoria), entonces, aunque la
Activity
desapareció, el sistema recuerda que existía. Si el usuario intenta volver a la actividad, el sistema crea una nueva instancia de esa actividad utilizando un conjunto de datos guardados que describen el estado de la actividad cuando finalizó.
Los datos guardados que el sistema usa para restablecer la
el estado anterior se denomina estado de la instancia. Es una colección de
Son pares clave-valor almacenados en un objeto Bundle
. De forma predeterminada, el
el sistema usa el estado de la instancia Bundle
para guardar información
sobre cada objeto View
en el diseño de tu actividad, como
el valor de texto ingresado en un
Widget EditText
De este modo, si finaliza y se vuelve a crear la instancia de tu actividad, se restablece el estado del diseño a su estado previo sin necesidad de que escribas el código. Sin embargo, es posible que tu actividad tenga más información de estado que desees restablecer, como variables de miembro que siguen el progreso del usuario en la actividad.
Nota: Para que el sistema Android restablezca el estado de las vistas de tu actividad, cada vista debe tener un ID único provisto por el atributo android:id
.
Un objeto Bundle
no es apropiado para preservar más de un
de datos, ya que requiere serialización en el subproceso principal y consume
la memoria del proceso del sistema. Para preservar más que una cantidad muy pequeña de datos,
un enfoque combinado para la preservación de datos,
el almacenamiento, el método onSaveInstanceState()
y el
Clase ViewModel
, como se describe en
Cómo guardar estados de la IU
Cómo guardar un estado de IU simple y ligero usando onSaveInstanceState()
A medida que comienza a detenerse tu actividad, el sistema llama al método onSaveInstanceState()
para que tu actividad pueda guardar la información del estado en un paquete de estado de instancia. La implementación predeterminada de ese método guarda información transitoria acerca del estado de la jerarquía de vistas de la actividad, como el texto de un widget EditText
o la posición de desplazamiento de un widget ListView
.
Para guardar información adicional sobre el estado de la instancia de tu actividad, anula
onSaveInstanceState()
y agrega pares clave-valor al objeto Bundle
que se guarda.
en caso de que tu actividad se destruya de forma inesperada. Cuando se anula
onSaveInstanceState()
, debes llamar a la implementación de la superclase.
si deseas que la implementación predeterminada guarde el estado de la jerarquía de vistas.
Esto se muestra en el siguiente ejemplo:
Kotlin
override fun onSaveInstanceState(outState: Bundle?) { // Save the user's current game state. outState?.run { putInt(STATE_SCORE, currentScore) putInt(STATE_LEVEL, currentLevel) } // Always call the superclass so it can save the view hierarchy state. super.onSaveInstanceState(outState) } companion object { val STATE_SCORE = "playerScore" val STATE_LEVEL = "playerLevel" }
Java
static final String STATE_SCORE = "playerScore"; static final String STATE_LEVEL = "playerLevel"; // ... @Override public void onSaveInstanceState(Bundle savedInstanceState) { // Save the user's current game state. savedInstanceState.putInt(STATE_SCORE, currentScore); savedInstanceState.putInt(STATE_LEVEL, currentLevel); // Always call the superclass so it can save the view hierarchy state. super.onSaveInstanceState(savedInstanceState); }
Nota:
onSaveInstanceState()
no es
se llama cuando el usuario cierra explícitamente la actividad o en otros casos cuando
Se llama a finish()
.
Para guardar datos persistentes, como preferencias del usuario o datos para una base de datos,
aprovechar las oportunidades adecuadas cuando la actividad se ejecuta en primer plano
Si no surge tal oportunidad, guarda los datos persistentes durante la
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 tras haber finalizado, puedes recuperar la instancia del estado guardado desde el Bundle
que el sistema pasa a tu actividad. Tanto el
onCreate()
y
onRestoreInstanceState()
métodos de devolución de llamada reciben el mismo Bundle
que contiene el
la información del estado de la instancia.
Dado que el método onCreate()
es
llamado si el sistema está creando una nueva instancia de tu actividad
o volver a crear una anterior, debes verificar si el estado Bundle
es nulo antes de que intentes leerlo. Si es nulo, el sistema creará una instancia nueva de la actividad en lugar de restablecer una previa que ya haya finalizado.
En el siguiente fragmento de código, se muestra cómo puedes restablecer algunos
datos de estado en onCreate()
:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Always call the superclass first // Check whether we're recreating a previously destroyed instance. if (savedInstanceState != null) { with(savedInstanceState) { // Restore value of members from saved state. currentScore = getInt(STATE_SCORE) currentLevel = getInt(STATE_LEVEL) } } else { // Probably initialize members with default values for a new instance. } // ... }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Always call the superclass first // Check whether we're recreating a previously destroyed instance. if (savedInstanceState != null) { // Restore value of members from saved state. currentScore = savedInstanceState.getInt(STATE_SCORE); currentLevel = savedInstanceState.getInt(STATE_LEVEL); } else { // Probably initialize members with default values for a new instance. } // ... }
En lugar de restablecer el estado durante
onCreate()
, puedes optar por implementar
onRestoreInstanceState()
, al que el sistema llama después de
onStart()
. El sistema llama
onRestoreInstanceState()
solo si hay un estado guardado para restablecer,
no es necesario verificar si Bundle
es nulo.
Kotlin
override fun onRestoreInstanceState(savedInstanceState: Bundle?) { // Always call the superclass so it can restore the view hierarchy. super.onRestoreInstanceState(savedInstanceState) // Restore state members from saved instance. savedInstanceState?.run { currentScore = getInt(STATE_SCORE) currentLevel = getInt(STATE_LEVEL) } }
Java
public void onRestoreInstanceState(Bundle savedInstanceState) { // Always call the superclass so it can restore the view hierarchy. super.onRestoreInstanceState(savedInstanceState); // Restore state members from saved instance. currentScore = savedInstanceState.getInt(STATE_SCORE); currentLevel = savedInstanceState.getInt(STATE_LEVEL); }
Precaución: Siempre llama a la implementación de la superclase de
onRestoreInstanceState()
por lo que la implementación predeterminada puede restablecer el estado de la jerarquía de vistas.
Navegación entre actividades
Es probable que una app entre y salga de una actividad, quizás muchas veces, durante la el ciclo de vida de la app, como cuando el usuario presiona el botón Atrás del dispositivo o la actividad inicia una diferente.
En esta sección, se abordan temas que necesitas saber para implementar transiciones de actividad que se realizaron correctamente. Estos temas incluyen iniciar una actividad desde otra, guardar el estado de la actividad y restablecer su estado.
Cómo iniciar una actividad desde otra
Es posible que una actividad necesite iniciar otra actividad en algún momento. Esta necesidad surge, por ejemplo, cuando una app necesita pasar de la pantalla actual a una nueva.
Dependiendo de si tu actividad desea o no un resultado de la nueva actividad
que está a punto de comenzar, puedes iniciar la nueva actividad usando el
startActivity()
startActivityForResult()
. En cualquier caso, debes pasar un objeto Intent
.
El objeto Intent
especifica
actividad que deseas iniciar o describe el tipo de acción que deseas realizar.
El sistema selecciona la actividad adecuada para ti, que incluso se puede
desde otra aplicación. Un objeto Intent
también puede contener pequeñas cantidades de datos que utilizará la actividad que se inicie.
Para obtener más información sobre la clase Intent
, consulta Intents y filtros de intents.
startActivity()
Si la actividad recién iniciada no necesita mostrar un resultado, la actividad actual puede iniciarla llamando al método startActivity()
.
Cuando trabajes en tu propia aplicación, con frecuencia necesitarás iniciar una actividad conocida.
Por ejemplo, el siguiente fragmento de código muestra cómo lanzar una actividad llamada SignInActivity
.
Kotlin
val intent = Intent(this, SignInActivity::class.java) startActivity(intent)
Java
Intent intent = new Intent(this, SignInActivity.class); startActivity(intent);
Tu aplicación también podría querer realizar alguna acción, como enviar un correo electrónico, mandar un mensaje de texto o actualizar su estado con datos de tu actividad. En ese caso, es posible que tu aplicación no tenga actividades propias para realizar esas acciones, por lo que, en su lugar, puedes aprovechar las actividades que proporcionan otras aplicaciones del dispositivo y que pueden realizar las acciones por ti.
Aquí es donde los intents son realmente valiosos. Puedes crear un que describe una acción que quieres realizar y el sistema inicia las actividad de otra aplicación. Si hay varias actividades que pueden controlar el intent, el usuario podrá seleccionar la que quiera usar. Por ejemplo, si quieres permitir que el usuario envíe un mensaje de correo electrónico, puedes crear el siguiente intent:
Kotlin
val intent = Intent(Intent.ACTION_SEND).apply { putExtra(Intent.EXTRA_EMAIL, recipientArray) } startActivity(intent)
Java
Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); startActivity(intent);
El EXTRA_EMAIL
adicional agregado al intent es un array de cadenas de
direcciones de correo electrónico a las que se debe enviar el correo electrónico. Cuando una aplicación de correo electrónico
responde a este intent, lee la matriz de cadenas proporcionada en el extra y
coloca las direcciones en el campo campo del formulario de redacción de correo electrónico. En este
correo electrónico, se inicia la actividad de la aplicación
de correo electrónico y, cuando el usuario haya terminado,
se reanuda tu actividad.
startActivityForResult()
En ocasiones, se desea obtener el resultado de una actividad cuando esta termina. Por ejemplo, puedes empezar
una actividad que permite al usuario elegir a una persona en una lista de contactos. Cuando termina, muestra
persona seleccionada. Para ello, llama al método startActivityForResult(Intent, int)
, donde el parámetro entero identifica la llamada.
Este identificador sirve para distinguir entre múltiples llamadas a
startActivityForResult(Intent, int)
de la misma actividad. No es un identificador global
y no corre el riesgo de entrar en conflicto con otras apps o actividades. El resultado se obtiene
onActivityResult(int, int, Intent)
.
Cuando se lleva a cabo una actividad secundaria, puedes llamar a setResult(int)
para mostrarle los datos a la actividad superior.
La actividad secundaria debe proporcionar un código de resultado, que pueden ser los resultados estándar.
RESULT_CANCELED
, RESULT_OK
o cualquier valor personalizado
a partir de RESULT_FIRST_USER
.
Además,
De manera opcional, la actividad secundaria puede mostrar un Intent
que contiene cualquier dato adicional que desee. La actividad superior usa
onActivityResult(int, int, Intent)
junto con el identificador de número entero que la actividad superior originalmente
para recibir la información.
Si una actividad secundaria falla por cualquier razón, por ejemplo, debido a un bloqueo, la actividad superior recibirá un resultado con el código RESULT_CANCELED
.
Kotlin
class MyActivity : Activity() { // ... override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { // When the user center presses, let them pick a contact. startActivityForResult( Intent(Intent.ACTION_PICK,Uri.parse("content://contacts")), PICK_CONTACT_REQUEST) return true } return false } override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { when (requestCode) { PICK_CONTACT_REQUEST -> if (resultCode == RESULT_OK) { // A contact was picked. Display it to the user. startActivity(Intent(Intent.ACTION_VIEW, intent?.data)) } } } companion object { internal val PICK_CONTACT_REQUEST = 0 } }
Java
public class MyActivity extends Activity { // ... static final int PICK_CONTACT_REQUEST = 0; public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { // When the user center presses, let them pick a contact. startActivityForResult( new Intent(Intent.ACTION_PICK, new Uri("content://contacts")), PICK_CONTACT_REQUEST); return true; } return false; } protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == PICK_CONTACT_REQUEST) { if (resultCode == RESULT_OK) { // A contact was picked. Display it to the user. startActivity(new Intent(Intent.ACTION_VIEW, data)); } } } }
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 Paused o Stopped, mientras se crea la otra actividad. Si esas actividades comparten datos guardados en el disco o en alguna otra parte, es importante que entiendas que no se detiene la primera actividad por completo antes de que se cree la segunda. Más bien, el proceso de iniciar la segunda se superpone con el proceso de detener la primera.
El orden de las devoluciones de llamada del ciclo de vida está bien definido, especialmente cuando las dos actividades en el mismo proceso (es decir, la misma aplicación) y uno inicia el otro. Aquí te mostramos el orden de las operaciones que ocurren cuando la actividad A inicia la actividad B:
- Se ejecuta el método
onPause()
de la actividad A. - Los métodos
onCreate()
,onStart()
yonResume()
de la actividad B se ejecutan en secuencia. La actividad B ahora está enfocada en el usuario. - 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.