Применение логики или оболочек к целевым страницам

Вы можете предоставить дополнительную информацию или применить ту же логику к пунктам назначения с помощью класса NavEntryDecorator. Этот класс оборачивает каждый элемент NavEntry в обратном стеке с помощью composable-функции. Иными словами, он украшает контент записи.

Как создать собственный декоратор

Чтобы создать декоратор, расширьте класс NavEntryDecorator и переопределите следующие методы:

  • decorate – composable-функция, которая вызывается для каждого элемента NavEntry в обратном стеке. Она получает NavEntry в качестве параметра. Это позволяет создавать объекты состояния, привязанные к contentKey записи. Вы можете использовать CompositionLocalProvider, чтобы предоставить зависимости для контента записи. Вы также можете окружить контент composable-функцией или запустить побочные эффекты. Внутри этого метода всегда нужно вызывать entry.Content().
  • onPop – обратный вызов, который активируется, когда NavEntry удаляется из обратного стека и покидает композицию. Она получает contentKey удаленной записи. Используйте contentKey, чтобы определить и удалить все состояния, связанные с этой записью.

В следующем примере класс NavEntryDecorator расширяется для создания пользовательского декоратора.

// 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") }
)

Если декоратору нужен доступ к состоянию, создайте composable-функцию, которая создает это состояние, а затем используйте ее для создания декоратора. Пример реализации можно найти в исходном коде rememberSaveableStateHolderNavEntryDecorator. Это создает состояние – SaveableStateHolder – и использует его для создания декоратора.

Как украсить обратный стек

Создав NavEntryDecorator, вы можете оформить записи в обратном стеке одним из двух способов:

  • используйте директиву rememberDecoratedNavEntries. Эта функция полезна, когда у вас есть несколько обратных стеков, каждый из которых имеет собственный набор декораторов (дополнительную информацию см. в этом рецепте кода). Функция возвращает декорированный список NavEntry, который можно использовать с NavDisplay.
  • Передайте декоратор непосредственно в NavDisplay с помощью параметра entryDecorators. NavDisplay вызывает rememberDecoratedNavEntries и показывает записи с дополнительной информацией.

Включить декоратор по умолчанию

В Navigation 3 есть декоратор по умолчанию SaveableStateHolderNavEntryDecorator, который позволяет сохранять состояние NavEntry при изменении конфигурации и завершении процесса. Он оборачивает контент NavEntry в SaveableStateProvider, что позволяет вызовам rememberSaveable внутри контента NavEntry работать правильно.

Если ваш декоратор не предоставляет SaveableStateProvider, вам следует включить SaveableStateHolderNavEntryDecorator в качестве первого декоратора в список предоставляемых декораторов. Оно создано с помощью rememberSaveableStateHolderNavEntryDecorator.

Пример:

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

Передача результатов с помощью ResultEventBusNavEntryDecorator

Начиная с Navigation 3 1.2.0, вы можете использовать ResultEventBusNavEntryDecorator, чтобы предоставить ResultEventBus каждому NavEntry с помощью локальной композиции LocalResultEventBus.

По умолчанию rememberResultEventBusNavEntryDecorator создает и запоминает собственный экземпляр ResultEventBus, используя rememberResultEventBus. Если вам нужен доступ к шине событий за пределами иерархии декораторов (например, на верхнем уровне приложения), вы можете поднять ResultEventBus, вызвав rememberResultEventBus и передав его в rememberResultEventBusNavEntryDecorator(resultEventBus):

val resultEventBus = rememberResultEventBus()

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

Подробнее о том, как отправлять и отслеживать результаты…

Когда использовать декоратор

Используйте декоратор, чтобы:

  • Создайте зависимость для каждого элемента NavEntry в обратном стеке. Например, ViewModelStoreNavEntryDecorator создает ViewModelStore для каждого NavEntry.
  • Передавайте результаты и обменивайтесь данными между целевыми страницами. Например, ResultEventBusNavEntryDecorator предоставляет ResultEventBus для пунктов назначения в обратном стеке.
  • Объект может относиться к нескольким NavEntry. Например, чтобы использовать один и тот же элемент ViewModel в нескольких записях.
  • Выполните одно и то же действие для нескольких объектов типа "NavEntry". Например, для ведения журнала, отладки или трассировки каждой записи.
  • Оберните NavEntry в одну и ту же composable-функцию.
  • Очистить состояние, связанное с NavEntry. Например, когда запись удаляется из обратного стека, ViewModelStoreNavEntryDecorator очищает связанный с ней ViewModelStore.

Не используйте декораторы, чтобы:

  • Передайте зависимость в один NavEntry.
  • Предоставляйте зависимости, область действия которых шире, чем обратный стек.

В обоих случаях передавайте зависимость напрямую при создании NavEntry.

Другие примеры кода можно найти в NavEntryDecorator.