Salvare e gestire lo stato di navigazione

Le seguenti sezioni descrivono le strategie per salvare la pila di ritorno e memorizzare lo stato associato alle voci nella pila di ritorno.

Salvare la pila precedente

Garantire la persistenza dello stato di navigazione dell'app in vari eventi del ciclo di vita, tra cui modifiche alla configurazione e interruzioni del processo, è fondamentale per un'esperienza utente positiva. In Navigazione 3, sei tu a possedere la pila di navigazione a ritroso, pertanto non esistono linee guida rigide su come crearla o salvarla. Tuttavia, Navigation 3 offre un metodo pratico che ti fornisce una pila di ritorno salvabile:rememberNavBackStack.

Utilizza rememberNavBackStack

La funzione componibile rememberNavBackStack è progettata per creare un back stack che persiste nelle modifiche alla configurazione e nell'interruzione del processo.

Affinché rememberNavBackStack funzioni correttamente, ogni chiave nella pila interna deve soddisfare requisiti specifici:

  • Implementa l'interfaccia NavKey: ogni chiave nello stack di ritorno deve implementare l'interfaccia NavKey. Questa interfaccia funge da indicatore che segnala alla biblioteca che la chiave può essere salvata.
  • Disporre dell'annotazione @Serializable: oltre a implementare NavKey, le classi e gli oggetti chiave devono essere contrassegnati con l'annotazione @Serializable.

Il seguente snippet mostra un'implementazione corretta di rememberNavBackStack:

@Serializable
data object Home : NavKey

@Composable
fun NavBackStack() {
    val backStack = rememberNavBackStack(Home)
}

Alternativa: archiviazione in un ViewModel

Un altro approccio per gestire la pila di ritorno è memorizzarla in un ViewModel. Per la persistenza dopo l'interruzione del processo quando utilizzi un ViewModel o qualsiasi altro spazio di archiviazione personalizzato, devi:

  • Assicurati che le chiavi siano serializzabili: come per rememberNavBackStack, le chiavi di navigazione devono essere serializzabili.
  • Gestisci la serializzazione e la deserializzazione manualmente: sei responsabile di salvare manualmente la rappresentazione serializzata di ogni chiave e deserializzarla dallo spazio di archiviazione permanente (ad es. SharedPreferences, un database o un file) quando l'app passa in background o viene ripristinata.

Scoping ViewModels to NavEntrys

ViewModels vengono utilizzati per mantenere lo stato relativo all'interfaccia utente durante le modifiche alla configurazione, come le rotazioni dello schermo. Per impostazione predefinita, i ViewModels sono limitati al ViewModelStoreOwner più vicino, in genere Activity o Fragment.

Tuttavia, ti consigliamo di limitare l'ambito di un ViewModel a un NavEntry specifico (ad es. una schermata o una destinazione specifica) nella pila precedente, anziché all'intero Activity. In questo modo, lo stato di ViewModel viene mantenuto solo mentre quel determinato ViewModel fa parte della pila di ritorno e viene cancellato quando ViewModel viene estratto.NavEntryNavEntry

La libreria dei componenti aggiuntivi androidx.lifecycle:lifecycle-viewmodel-navigation3 fornisce un NavEntryDecorator che semplifica questa operazione. Questo decoratore fornisce un ViewModelStoreOwner per ogni NavEntry. Quando crei un ViewModel all'interno dei contenuti di un NavEntry (ad es. utilizzando viewModel() in Componi), l'ambito viene automaticamente impostato sulla chiave di quel NavEntry specifico nello stack precedente. Ciò significa che ViewModel viene creato quando NavEntry viene aggiunto allo stack precedente e viene cancellato quando viene rimosso.

Per utilizzare NavEntryDecorator per limitare l'ambito dei ViewModel ai NavEntry, segui questi passaggi:

  1. Aggiungi la dipendenza androidx.lifecycle:lifecycle-viewmodel-navigation3 al tuo file app/build.gradle.kts.
  2. Aggiungi rememberSavedStateNavEntryDecorator() all'elenco di entryDecorators durante la costruzione di un NavDisplay.
  3. Aggiungi altri decorazioni a 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 { },
)