Salvare e gestire lo stato di navigazione

Le sezioni seguenti descrivono le strategie per salvare lo stack precedente e memorizzare lo stato associato alle voci dello stack precedente.

Salvare lo stack di navigazione

Garantire che lo stato di navigazione dell'app persista in vari eventi del ciclo di vita, inclusi modifiche alla configurazione e interruzione del processo, è fondamentale per una buona esperienza utente. In Navigation 3, lo stack precedente è di tua proprietà, quindi non esistono linee guida rigide su come crearlo o salvarlo. Tuttavia, Navigation 3 offre un metodo pratico che ti fornisce uno stack indietro salvabile: rememberNavBackStack.

Utilizza rememberNavBackStack

La funzione componibile rememberNavBackStack è progettata per creare uno stack che persiste in caso di modifiche alla configurazione e interruzione del processo.

Affinché rememberNavBackStack funzioni correttamente, ogni chiave nello stack precedente deve rispettare requisiti specifici:

  • Implementa l'interfaccia NavKey: ogni chiave nello stack precedente deve implementare l'interfaccia NavKey. che funge da interfaccia di marcatore che segnala alla libreria che la chiave può essere salvata.
  • Avere l'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 lo stack di navigazione è memorizzarlo in un ViewModel. Per la persistenza in caso di interruzione del processo quando utilizzi ViewModel o qualsiasi altro spazio di archiviazione personalizzato, devi:

  • Assicurati che le chiavi siano serializzabili: proprio come con rememberNavBackStack, le chiavi di navigazione devono essere serializzabili.
  • Gestisci manualmente la serializzazione e la deserializzazione: sei responsabile del salvataggio manuale della rappresentazione serializzata di ogni chiave e della sua deserializzazione 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 in seguito a modifiche alla configurazione, come le rotazioni dello schermo. Per impostazione predefinita, gli ViewModels sono limitati all'ViewModelStoreOwner più vicino, che in genere è il tuo Activity o Fragment.

Tuttavia, potresti voler limitare un ViewModel a un NavEntry specifico (ad es. una schermata o una destinazione specifica) nello stack precedente, anziché all'intero Activity. In questo modo, lo stato di ViewModel viene mantenuto solo mentre NavEntry fa parte dello stack precedente e viene cancellato quando NavEntry viene rimosso.

La libreria di componenti aggiuntivi androidx.lifecycle:lifecycle-viewmodel-navigation3 fornisce un NavEntryDecorator che facilita 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 Composizione), l'ambito viene automaticamente limitato alla chiave di quel NavEntry specifico nello stack precedente. Ciò significa che l'ViewModel viene creato quando l'NavEntry viene aggiunto allo stack precedente e cancellato quando viene rimosso.

Per utilizzare NavEntryDecorator per definire l'ambito delle ViewModel in base alle NavEntry, segui questi passaggi:

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