使用元数据配置应用

在 Navigation 3 中,您可以使用元数据在不同的库组件(例如 NavEntry、Scene 和 NavDisplay)之间共享任意信息。最基本的元数据是 Map<String, Any>。不过,该库提供了额外的抽象,使元数据的读取和写入更简单、更安全。

提供 NavEntry 元数据

如果您的应用直接构建其 NavEntry 实例,您可以使用 metadata 构造函数参数为条目提供元数据:

when (key) {
    is Home -> NavEntry(key, metadata = mapOf("key" to "value")) {}
}

如果您的应用使用 entryProvider DSL,您可以通过 entry 函数的 metadata 参数提供元数据。此函数有两种重载:一种直接接受映射,另一种接受将条目的键作为参数传递的 lambda:

entry<Home>(metadata = mapOf("key" to "value")) { /* ... */ }
entry<Conversation>(metadata = { key: Conversation ->
    mapOf("key" to "value: ${key.id})")
}) { /* ... */ }

提供 Scene 元数据

默认情况下,Scene.metadata 使用自定义 getter,该 getter 会返回其 entries 属性中最后一个条目的 metadata,如果该条目为 null,则返回一个空映射。实现 Scene 接口时,您可以根据需要替换此默认行为。

使用元数据 DSL

元数据领域特定语言 (DSL) 是在库的 1.1.0-beta01 版本中引入的,它提供了一个类型安全的构建器,用于创建存储元数据所用的 Map<String, Any>。

定义元数据键

DSL 依赖于 NavMetadataKey 接口,以使与元数据键关联的值的类型保持一致。

定义元数据键的惯例是将其作为类(或在函数或可组合项的情况下,作为相关对象)的嵌套对象包含在内,这些类或对象将读取与这些键关联的值:

// For classes such as scene strategies or nav entry decorators, you can define the keys
// as nested object.
class MySceneStrategy<T : Any> : SceneStrategy<T> {

    // ...

    object MyStringMetadataKey : NavMetadataKey<String>
}

// An example from NavDisplay.
// Because NavDisplay is a function, the metadata keys are defined in an object with the same name.
public object NavDisplay {

    public object TransitionKey :
        NavMetadataKey<AnimatedContentTransitionScope<Scene<*>>.() -> ContentTransform>
}

使用 DSL 构建元数据

如需创建元数据映射,请使用 metadata 函数,该函数接受 lambda 参数。在此 lambda 中,使用 put 函数,通过 NavMetadataKey 和对应的值向映射添加条目。

entry<Home>(
    metadata = metadata {
        put(NavDisplay.TransitionKey) { fadeIn() togetherWith fadeOut() }
        // An additional benefit of the metadata DSL is the ability to use conditional logic
        if (condition) {
            put(MySceneStrategy.MyStringMetadataKey, "Hello, world!")
        }
    }
) {
    // ...
}

使用元数据键读取元数据

元数据 DSL 还提供了使用 NavMetadataKey 简化元数据读取的函数。

// import androidx.navigation3.runtime.contains
// import androidx.navigation3.runtime.get

val hasMyString: Boolean = metadata.contains(MySceneStrategy.MyStringMetadataKey)
val myString: String? = metadata[MySceneStrategy.MyStringMetadataKey]