You can provide extra information or apply the same logic to
destinations using the NavEntryDecorator class. This class wraps each
NavEntry in a back stack with a composable function. Put another way,
it decorates the entry's content.
Create a custom decorator
To create a decorator, extend the NavEntryDecorator class and override
the following methods:
decorate- A composable lambda that is called for eachNavEntryin your back stack. It receives theNavEntryas a parameter. This lets you to create state objects that are keyed to the entry'scontentKey. You can useCompositionLocalProviderto provide dependencies to the entry's content. You can also surround the content with a composable function, or trigger side-effects. You should always callentry.Content()inside this method.onPop- A callback that is invoked when aNavEntryhas been removed from the back stack and has left the composition. It receives thecontentKeyof the removed entry. Use thecontentKeyto identify and clean up any state associated with that entry.
The following example extends the NavEntryDecorator class to create a custom
decorator.
// 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") } )
If your decorator needs access to state, create a composable function that
creates that state then use it to construct the decorator. For an example
implementation, see the source code for
rememberSaveableStateHolderNavEntryDecorator. This creates
the state - a SaveableStateHolder - and uses it to construct the decorator.
Decorate a back stack
Once you've created your NavEntryDecorator, decorate the entries in your
back stack in one of two ways:
- Use
rememberDecoratedNavEntries. This function is useful when you have multiple back stacks, each with its own set of decorators (see this code recipe for more details). The function returns a decorated list ofNavEntrys that you can use withNavDisplay. - Supply your decorator directly to
NavDisplayusing theentryDecoratorsparameter.NavDisplaycallsrememberDecoratedNavEntriesunder the hood and displays the decorated entries.
Include the default decorator
Navigation 3 includes a default decorator named
SaveableStateHolderNavEntryDecorator that enables a NavEntry's state to
be retained through configuration changes and process death. It wraps
NavEntry content with a SaveableStateProvider, which enables
rememberSaveable calls inside the NavEntry content to function correctly.
Unless your decorator is providing a SaveableStateProvider, you should
include SaveableStateHolderNavEntryDecorator as the first decorator in your
list of supplied decorators. It is created using
rememberSaveableStateHolderNavEntryDecorator.
For example:
// import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator NavDisplay( entryDecorators = listOf( rememberSaveableStateHolderNavEntryDecorator(), remember { CustomNavEntryDecorator() } ), // ... )
When to use a decorator
Use a decorator to:
- Create a dependency for every
NavEntryin a back stack. For example, theViewModelStoreNavEntryDecoratorcreates aViewModelStorefor everyNavEntry. - Scope an object to multiple
NavEntrys. For example, to share aViewModelbetween multiple entries. - Perform the same action for multiple
NavEntrys. For example, to perform logging, debugging or tracing operations for each entry. - Wrap
NavEntrys with the same composable function. - Clean up state associated with
NavEntrys. For example, when an entry is removed from the back stack theViewModelStoreNavEntryDecoratorclears its associatedViewModelStore.
Don't use a decorator to:
- Pass a dependency to a single
NavEntry. - Provide dependencies whose scope is broader than the back stack.
In both these cases, pass the dependency directly when creating the NavEntry
instead.
For more code examples, see NavEntryDecorator.