【问题标题】:Jetpack Compose Navigation - pass argument to startDestinationJetpack Compose Navigation - 将参数传递给 startDestination
【发布时间】:2022-01-21 00:30:02
【问题描述】:

我正在构建的应用程序使用带有路线的组合导航。挑战在于起点是动态的。

这是一个最小的例子:

class MainActivity : ComponentActivity()
{
    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)

        setContent {
            val navController = rememberNavController()

            NavHost(
                navController = navController,
                startDestination = "dynamic/1", // doesn't work
                // startDestination = "static", // workaround
            ) {
                composable(
                    route = "dynamic/{$ARG_ID}",
                    arguments = listOf(navArgument(ARG_ID) { type = NavType.StringType }),
                ) {
                    val id = it.arguments?.getString(ARG_ID)
                    Text("dynamic route, received argument: $id!")
                }
                // part of the workaround
                // composable(
                //  route = "static",
                // ) {
                //  LaunchedEffect(this) {
                //      navController.navigate("dynamic/1")
                //  }
                // }
            }
        }
    }

    companion object
    {
        const val ARG_ID = "id"
    }
}

应用程序崩溃

java.lang.IllegalArgumentException: navigation destination route/1 is not a direct child of this NavGraph

仅当“动态”路由用作起始目的地时才会存在问题。这可以通过使用startDestination = "static" 来验证。

虽然,“静态”路由解决方法有效,但我正在寻找没有它的解决方案,因为它会混淆代码并在后台堆栈中创建一个额外的条目。

-> Full code sample 重现问题

相关的 SO 问题

编辑:

我想强调的是,原始样本过去不包含“静态”可组合。我只添加了“静态”可组合项以使 startDestination 正常工作并证明“动态”可组合项可以导航到。

更新:

即使切换到query parameter syntax for optional arguments,提供默认值,不带任何参数设置起始目的地也不起作用。

以下变化

NavHost(
    navController = navController,
    startDestination = "dynamic",
) {
    composable(
        route = "dynamic?$ARG_ID={$ARG_ID}",
        arguments = listOf(navArgument(ARG_ID) { type = NavType.StringType; defaultValue = "1" }),
    ) {
        val id = it.arguments?.getString(ARG_ID)
        Text("dynamic route, received argument: $id!")
    }
}

导致异常

java.lang.IllegalArgumentException: navigation destination dynamic is not a direct child of this NavGraph

【问题讨论】:

  • 这能回答你的问题吗? Compose Navigation - navigation destination ... is not a direct child of this NavGraph(来自 Compose 维护者的回答)
  • @PhilipDukhov 不,不幸的是它没有。阅读所有 cmets 接受的答案似乎并没有完全解决那里的原始问题......或者你有没有发现我可以应用于我的样本的东西?我将把问题添加到我的相关问题列表中。
  • 与其让static 调用navController.navigate("dynamic/1"),不如让它调用您为动态场景可组合的真实内容,将"1" 作为硬编码值传入,而不是从参数Bundle。这样就避免了后栈中的额外条目,而且看起来也不是特别复杂。
  • “能否请您详细说明在哪里调用 navController.navigate("dynamic/1")" - 我建议 不要 这样做。保留static 路由,但让它调用与dynamic 路由相同的函数,只是使用硬编码的"1" 参数,而不是从参数包中获取值。
  • 您用于startDestination 的字符串"dynamic" 需要逐个字符地匹配您在composable route 中使用的确切字符串:它必须是"dynamic?$ARG_ID={$ARG_ID}"

标签: android android-jetpack-compose android-jetpack-navigation android-navigation-graph


【解决方案1】:

完全归功于ianhanniballake,他在评论中向我解释了解决方案。我将在这里展示我的代码示例的工作版本。

对我来说最大的见解是:

startDestination 不能匹配模式匹配意义上的可组合route,但它必须是完全相同的字符串

这意味着不能直接通过startDestination 设置参数,而必须通过参数的defaultValue 设置。

这是工作示例:

class MainActivity : ComponentActivity()
{
    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)

        setContent {
            val navController = rememberNavController()

            NavHost(
                navController = navController,
                // 1st change: Set startDestination to the exact string of route
                startDestination = "dynamic/{$ARG_ID}", // NOT "dynamic/1", provide arguments via defaultValue
            ) {
                composable(
                    route = "dynamic/{$ARG_ID}",
                    // 2nd change: Set startDestination argument via defaultValue
                    arguments = listOf(navArgument(ARG_ID) { type = NavType.StringType; defaultValue = "1" }),
                ) {
                    val id = it.arguments?.getString(ARG_ID)
                    Text("dynamic route, received argument: $id!")
                }
            }
        }
    }

    companion object
    {
        const val ARG_ID = "id"
    }
}

该方法同样适用于以查询参数形式提供的参数。

老实说,我认为这是一个小限制,因为现在开始路线决定了必须是 defaultValue。我可能想设置一个不同的defaultValue 或根本没有。然而,在大多数情况下,这应该是最优雅的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-31
    • 1970-01-01
    • 2022-09-25
    • 1970-01-01
    • 1970-01-01
    • 2018-10-24
    • 1970-01-01
    相关资源
    最近更新 更多