Jetpack Compose Navigation - 将参数传递给 startDestination

Pet*_*r F 29 android android-jetpack-navigation android-jetpack-compose android-navigation-graph

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

这是一个最小的例子:

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"
    }
}
Run Code Online (Sandbox Code Playgroud)

该应用程序崩溃了

java.lang.IllegalArgumentException: navigation destination route/1 is not a direct child of this NavGraph
Run Code Online (Sandbox Code Playgroud)

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

虽然“静态”路由解决方法有效,但我正在寻找一种没有它的解决方案,因为它会混淆代码,并且还会在返回堆栈中创建一个附加条目。

->重现问题的完整代码示例

相关问题

编辑:

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

更新:

即使切换到可选参数的查询参数语法、提供默认值以及设置不带任何参数的起始目标也不起作用。

以下变体

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!")
    }
}
Run Code Online (Sandbox Code Playgroud)

导致异常

java.lang.IllegalArgumentException: navigation destination dynamic is not a direct child of this NavGraph
Run Code Online (Sandbox Code Playgroud)

Pet*_*r F 47

完全归功于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"
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • @ianhanniballake 如果能在官方文档中包含这些信息就太好了 (7认同)
  • 一天结束!我们无法动态更改默认值。对于 __startDestination__ (5认同)
  • 感谢您的回答,您的假设也是我的直觉;如果 Compose Navigation 的操作方式与 URL 导航类似,我认为它会以这种方式工作。我同意@MTomczynski,这种边缘情况应该在官方文档中。 (4认同)