向目的地应用逻辑或封装容器

您可以使用 NavEntryDecorator 类提供额外信息或将相同的逻辑应用于目的地。此类使用可组合函数封装返回堆栈中的每个 NavEntry。换句话说,它会修饰条目的内容。

创建自定义装饰器

如需创建装饰器,请扩展 NavEntryDecorator 类并替换以下方法:

  • decorate - 一个可组合 lambda,会针对返回堆栈中的每个 NavEntry 调用。它会接收 NavEntry 作为参数。这样,您就可以创建以条目的 contentKey 为键的状态对象。您可以使用 CompositionLocalProvider 为条目的内容提供依赖项。 您还可以使用可组合函数封装内容,或触发附带效应。您应始终在此方法内调用 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") }
)

如果修饰器需要访问状态,请创建一个可组合函数来创建该状态,然后使用该状态来构造修饰器。如需查看实现示例,请参阅 rememberSaveableStateHolderNavEntryDecorator 的源代码。这会创建状态(SaveableStateHolder),并使用它来构造修饰器。

修饰返回堆栈

创建 NavEntryDecorator 后,您可以通过以下两种方式之一修饰返回堆栈中的条目:

  • 使用rememberDecoratedNavEntries。当您有多个返回堆栈且每个返回堆栈都有自己的一组修饰符时,此函数非常有用(如需了解详情,请参阅此代码方案)。该函数会返回一个修饰过的 NavEntry 列表,您可以将其与 NavDisplay 搭配使用。
  • 使用 entryDecorators 参数直接向 NavDisplay 提供修饰器。NavDisplay 在后台调用 rememberDecoratedNavEntries 并显示修饰后的条目。

添加默认修饰器

Navigation 3 包含一个名为 SaveableStateHolderNavEntryDecorator 的默认修饰器,该修饰器可让 NavEntry 的状态在配置更改和进程终止后得以保留。它使用 SaveableStateProvider 封装 NavEntry 内容,从而使 NavEntry 内容中的 rememberSaveable 调用能够正常运行。

除非您的装饰器提供 SaveableStateProvider,否则您应将 SaveableStateHolderNavEntryDecorator 作为所提供装饰器列表中的第一个装饰器。它是使用 rememberSaveableStateHolderNavEntryDecorator 创建的。

例如:

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

使用 ResultEventBusNavEntryDecorator 传递结果

从 Navigation 3 1.2.0 开始,您可以使用 ResultEventBusNavEntryDecorator 通过 LocalResultEventBus 组合局部变量为每个 NavEntry 提供 ResultEventBus。

默认情况下,rememberResultEventBusNavEntryDecorator 会在内部使用 rememberResultEventBus 创建并记住自己的 ResultEventBus 实例。如果您需要在修饰符层次结构之外(例如在顶级应用框架中)访问事件总线,可以通过调用 rememberResultEventBus 并将其传递给 rememberResultEventBusNavEntryDecorator(resultEventBus) 来提升 ResultEventBus:

val resultEventBus = rememberResultEventBus()

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

如需详细了解如何发送和观察结果,请参阅返回结果。

何时使用修饰器

使用修饰器可以:

  • 为返回堆栈中的每个 NavEntry 创建一个依赖项。例如,ViewModelStoreNavEntryDecorator 会为每个 NavEntry 创建一个 ViewModelStore。
  • 在目的地之间传递结果和进行通信。例如,ResultEventBusNavEntryDecorator 为返回堆栈中的目的地提供 ResultEventBus。
  • 将一个对象限定为多个 NavEntry。例如,在多个条目之间共享 ViewModel。
  • 对多个 NavEntry 执行相同的操作。例如,为每个条目执行日志记录、调试或跟踪操作。
  • 使用相同的可组合函数封装 NavEntry。
  • 清理与 NavEntry 关联的状态。例如,当某个条目从返回堆栈中移除时,ViewModelStoreNavEntryDecorator 会清除其关联的 ViewModelStore。

请勿使用修饰器执行以下操作:

  • 将依赖项传递给单个 NavEntry。
  • 提供范围比返回堆栈更广的依赖项。

在这两种情况下,请改为在创建 NavEntry 时直接传递依赖项。

如需查看更多代码示例,请参阅 NavEntryDecorator。