Applicare logica o wrapper alle destinazioni

Puoi fornire informazioni aggiuntive o applicare la stessa logica alle destinazioni utilizzando la classe NavEntryDecorator. Questa classe racchiude ogni NavEntry in un back stack con una funzione componibile. In altre parole, decora i contenuti della voce.

Crea un decoratore personalizzato

Per creare un decoratore, estendi la classe NavEntryDecorator ed esegui l'override dei seguenti metodi:

  • decorate: una funzione lambda composable chiamata per ogni NavEntry nello stack indietro. Riceve NavEntry come parametro. In questo modo, puoi creare oggetti di stato associati all'attributo contentKey della voce. Puoi utilizzare CompositionLocalProvider per fornire dipendenze ai contenuti della voce. Puoi anche racchiudere i contenuti in una funzione componibile o attivare effetti collaterali. Devi sempre chiamare entry.Content() all'interno di questo metodo.
  • onPop: un callback richiamato quando un NavEntry è stato rimosso dallo stack precedente e ha lasciato la composizione. Riceve il contentKey della voce rimossa. Utilizza contentKey per identificare e liberare spazio associato a questa voce.

L'esempio seguente estende la classe NavEntryDecorator per creare un decoratore personalizzato.

// import androidx.navigation3.runtime.NavEntryDecorator
class CustomNavEntryDecorator<T : Any> : NavEntryDecorator<T>(
    decorate = { entry ->
        Log.d("CustomNavEntryDecorator", "entry with ${entry.contentKey} entered composition and was decorated")
        entry.Content()
    },
    onPop = { contentKey -> Log.d("CustomNavEntryDecorator", "entry with $contentKey was popped") }
)

Se il decoratore deve accedere allo stato, crea una funzione componibile che crea lo stato e poi lo utilizza per costruire il decoratore. Per un esempio di implementazione, vedi il codice sorgente di rememberSaveableStateHolderNavEntryDecorator. In questo modo viene creato lo stato, ovvero un SaveableStateHolder, che viene utilizzato per costruire il decoratore.

Decorare uno stack di ritorno

Dopo aver creato l'NavEntryDecorator, decora le voci dello stack precedente in uno dei due modi seguenti:

  • Utilizza rememberDecoratedNavEntries. Questa funzione è utile quando hai più back stack, ognuna con il proprio set di decoratori (per maggiori dettagli, consulta questa ricetta di codice). La funzione restituisce un elenco decorato di NavEntry che puoi utilizzare con NavDisplay.
  • Fornisci il decoratore direttamente a NavDisplay utilizzando il parametro entryDecorators. NavDisplay calls rememberDecoratedNavEntries under the hood and displays the decorated entries.

Includere il decoratore predefinito

Navigation 3 include un decoratore predefinito denominato SaveableStateHolderNavEntryDecorator che consente di mantenere lo stato di un NavEntry durante le modifiche alla configurazione e l'interruzione del processo. Il wrapper NavEntry include un SaveableStateProvider, che consente alle chiamate rememberSaveable all'interno dei contenuti NavEntry di funzionare correttamente.

A meno che il tuo decoratore non fornisca un SaveableStateProvider, devi includere SaveableStateHolderNavEntryDecorator come primo decoratore nell'elenco dei decoratori forniti. È stato creato utilizzando rememberSaveableStateHolderNavEntryDecorator.

Ad esempio:

// import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
NavDisplay(
    entryDecorators = listOf(
        rememberSaveableStateHolderNavEntryDecorator(),
        remember { CustomNavEntryDecorator() }
    ),
    // ...
)

Risultati del test utilizzando ResultEventBusNavEntryDecorator

A partire dalla navigazione 3 1.2.0, puoi utilizzare ResultEventBusNavEntryDecorator per fornire un ResultEventBus a ogni NavEntry utilizzando la LocalResultEventBus composizione locale.

Per impostazione predefinita, rememberResultEventBusNavEntryDecorator crea e memorizza internamente la propria istanza ResultEventBus utilizzando rememberResultEventBus. Se devi accedere al bus degli eventi al di fuori della gerarchia dei decoratori (ad esempio nell'impalcatura dell'app di primo livello), puoi sollevare ResultEventBus chiamando rememberResultEventBus e passandolo a rememberResultEventBusNavEntryDecorator(resultEventBus):

val resultEventBus = rememberResultEventBus()

NavDisplay(
    /* ... */
    entryDecorators = listOf(
        rememberSaveableStateHolderNavEntryDecorator(),
        rememberResultEventBusNavEntryDecorator(resultEventBus = resultEventBus)
    )
)

Per ulteriori dettagli sull'invio e l'osservazione dei risultati, vedi Restituisci risultati.

Quando utilizzare un decoratore

Utilizza un decoratore per:

  • Crea una dipendenza per ogni NavEntry in un back stack. Ad esempio, ViewModelStoreNavEntryDecorator crea un ViewModelStore per ogni NavEntry.
  • Passare i risultati e comunicare tra le destinazioni. Ad esempio, l'intent ResultEventBusNavEntryDecorator fornisce un ResultEventBus alle destinazioni nel back stack.
  • Definisci l'ambito di un oggetto per più NavEntry. Ad esempio, per condividere un ViewModel tra più voci.
  • Esegui la stessa azione per più NavEntry. Ad esempio, per eseguire operazioni di logging, debug o tracciamento per ogni voce.
  • Esegui il wrapping di NavEntry con la stessa funzione componibile.
  • Libera spazio associato a NavEntry. Ad esempio, quando una voce viene rimossa dal back stack, l'ViewModelStoreNavEntryDecorator cancella il relativo ViewModelStore.

Non utilizzare un decoratore per:

  • Passa una dipendenza a un singolo NavEntry.
  • Fornisci dipendenze il cui ambito è più ampio del back stack.

In entrambi i casi, passa la dipendenza direttamente durante la creazione di NavEntry.

Per altri esempi di codice, vedi NavEntryDecorator.