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

Вы можете добавить дополнительную информацию или применить ту же логику к целевым страницам, используя класс 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

Начиная с версии 3 1.2.0 библиотеки Navigation, вы можете использовать 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. Например, для регистрации, отладки или трассировки каждой записи.
  • Оберните NavEntrys в одну и ту же composable-функцию.
  • Удалите данные, связанные с NavEntry. Например, когда запись удаляется из стека возврата, ViewModelStoreNavEntryDecorator очищает связанный с ней ViewModelStore.

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

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

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

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