En las siguientes secciones, se describen estrategias para guardar tu pila de historial y almacenar el estado asociado a las entradas de la pila de historial.
Cómo guardar la pila de actividades
Garantizar que el estado de navegación de tu app persista en varios eventos del ciclo de vida, incluidos los cambios de configuración y la finalización del proceso, es fundamental para una buena experiencia del usuario. En Navigation 3, eres propietario de tu pila de historial, por lo que no hay lineamientos estrictos sobre cómo debes crearla o guardarla. Sin embargo, Navigation 3 ofrece un método conveniente que te proporciona una pila de actividades que se puede guardar: rememberNavBackStack.
Usa rememberNavBackStack
La función de componibilidad rememberNavBackStack está diseñada para crear una pila de historial que persiste en los cambios de configuración y el cierre del proceso.
Para que rememberNavBackStack funcione correctamente, cada clave de tu pila de actividades debe cumplir con requisitos específicos:
- Implementa la interfaz
NavKey: Cada clave en la pila de historial debe implementar la interfazNavKey. Actúa como una interfaz de marcador que indica a la biblioteca que se puede guardar la clave. - Tener la anotación
@Serializable: Además de implementarNavKey, tus clases y objetos clave deben estar marcados con la anotación@Serializable.
En el siguiente fragmento, se muestra una implementación correcta de rememberNavBackStack:
@Serializable data object Home : NavKey @Composable fun NavBackStack() { val backStack = rememberNavBackStack(Home) }
Alternativa: Almacenamiento en un ViewModel
Otro enfoque para administrar la pila de actividades es almacenarla en un ViewModel.
Para la persistencia a través del cierre de procesos cuando se usa ViewModel o cualquier otro almacenamiento personalizado, debes hacer lo siguiente:
- Asegúrate de que tus claves sean serializables: Al igual que con
rememberNavBackStack, tus claves de navegación deben ser serializables. - Controla la serialización y deserialización de forma manual: Eres responsable de guardar manualmente la representación serializada de cada clave en el almacenamiento persistente y deserializarla desde él (p.ej.,
SharedPreferences, una base de datos o un archivo) cuando tu app pasa a segundo plano o se restablece.
Cómo definir el alcance de los períodos de ViewModel a NavEntry
Los ViewModels se usan para conservar el estado relacionado con la IU en los cambios de configuración, como las rotaciones de pantalla. De forma predeterminada, los ViewModels se limitan al ViewModelStoreOwner más cercano, que suele ser tu Activity o Fragment.
Sin embargo, es posible que desees definir el alcance de un ViewModel para un NavEntry específico (es decir, una pantalla o un destino específico) en la pila de historial, en lugar de todo el Activity. Esto garantiza que el estado de ViewModel se conserve solo mientras ese NavEntry en particular forme parte de la pila de actividades y se borre cuando se quite el NavEntry.
La biblioteca de complementos androidx.lifecycle:lifecycle-viewmodel-navigation3 proporciona un NavEntryDecorator que facilita esta tarea. Este decorador proporciona un ViewModelStoreOwner para cada NavEntry. Cuando creas un ViewModel dentro del contenido de un NavEntry (p.ej., con viewModel() en Compose), se define automáticamente el alcance para la clave de ese NavEntry específico en la pila de actividades. Esto significa que el ViewModel se crea cuando el NavEntry se agrega a la pila de actividades anteriores y se borra cuando se quita.
Para usar NavEntryDecorator para definir el alcance de los ViewModel en los NavEntry, sigue estos pasos:
- Agrega la dependencia
androidx.lifecycle:lifecycle-viewmodel-navigation3a tu archivoapp/build.gradle.kts. - Agrega
rememberSaveableStateHolderNavEntryDecorator()a la lista deentryDecoratorscuando construyas unNavDisplay. - Agrega otros decoradores a tu
NavDisplay.
NavDisplay( entryDecorators = listOf( // Add the default decorators for managing scenes and saving state rememberSceneSetupNavEntryDecorator(), rememberSavedStateNavEntryDecorator(), // Then add the view model store decorator rememberViewModelStoreNavEntryDecorator() ), backStack = backStack, entryProvider = entryProvider { }, )