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

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

创建自定义装饰器

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

  • decorate - 为返回堆栈中的每个 NavEntry 调用的可组合 lambda。它会接收 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() }
    ),
    // ...
)

何时使用装饰器

使用装饰器可以:

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

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

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

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

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