[英]Jetpack Compose Navigation - pass argument to startDestination
The app I'm building uses compose navigation with routes.我正在构建的应用程序使用带路线的组合导航。 The challenge is that the start destination is dynamic.
挑战在于起始目的地是动态的。
Here is a minimal example:这是一个最小的例子:
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"
}
}
The app crashes with该应用程序崩溃
java.lang.IllegalArgumentException: navigation destination route/1 is not a direct child of this NavGraph
The problem only exists if the "dynamic" route is used as start destination.该问题仅在“动态”路线用作起始目的地时才存在。 This can be verified by using
startDestination = "static"
.这可以通过使用
startDestination = "static"
来验证。
Although, the "static" route workaround works I'm looking for a solution without it because it kind of obfuscates the code and also creates an additional entry in the back stack.虽然,“静态”路由解决方法有效,但我正在寻找没有它的解决方案,因为它有点混淆了代码,并且还在后台堆栈中创建了一个额外的条目。
-> Full code sample to reproduce the issue -> 重现问题的完整代码示例
Related SO questions相关问题
Edit:编辑:
I want to stress that the original sample used to not contain the "static" composable.我想强调的是,原始示例过去不包含“静态”可组合项。 I only added the "static" composable to have a working
startDestination
and to prove that the "dynamic" composable can be navigated to.我只添加了“静态”可组合项以获得有效的
startDestination
并证明可以导航到“动态”可组合项。
Update:更新:
Even switching to the query parameter syntax for optional arguments , providing a default value, and setting the start destination without any argument does not work.即使切换到可选 arguments 的查询参数语法,提供默认值,并设置没有任何参数的起始目的地也不起作用。
The following variation以下变化
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!")
}
}
Leads to the exception导致异常
java.lang.IllegalArgumentException: navigation destination dynamic is not a direct child of this NavGraph
Full credit goes to ianhanniballake , who explained the solution to me in a comment.完全归功于ianhanniballake ,他在评论中向我解释了解决方案。 I'm going to show the working version of my code sample here.
我将在这里展示我的代码示例的工作版本。
The big insight to me was:对我来说最大的见解是:
startDestination
must not match a composable route
in the sense of pattern matching but it must be exactly the same string . startDestination
不能匹配模式匹配意义上的可组合route
,但它必须是完全相同的字符串。
That means an argument can't be set via startDestination
directly but has to be set via the argument's defaultValue
.这意味着参数不能直接通过
startDestination
设置,而必须通过参数的defaultValue
设置。
Here is the working sample:这是工作示例:
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"
}
}
The approach equally works with the argument provided in the form of a query parameter.该方法同样适用于以查询参数形式提供的参数。
To be honest, I see this as a small limitation because the start route now dictates what has to be the defaultValue
.老实说,我认为这是一个小限制,因为现在开始路线决定了
defaultValue
必须是什么。 I might want to set a different defaultValue
or none at all.我可能想设置一个不同的
defaultValue
或根本没有。 Yet, in most cases this should be the most elegant solution.然而,在大多数情况下,这应该是最优雅的解决方案。
should not be using dynamic route value in "startDestination" NavHost --> navController.navigate(<dynamic route >)不应在“startDestination”NavHost 中使用动态路由值 --> navController.navigate(<dynamic route >)
All credit goes to ianhanniballake and Peter .所有功劳归功于ianhanniballake和Peter 。 In my case I didn't add any additional (mandatory key/optional key) in route for the argument data.
在我的例子中,我没有在参数数据的路由中添加任何额外的(强制键/可选键)。 I kept the route clean like below:
我保持路线清洁,如下所示:
Nav graph:导航图:
navigation(route = Route.Root.route, startDestination = Route.SubmitForm.route) {
composable(
route = Route.SubmitForm.route,
arguments = listOf(
navArgument(ARG_KEY) {
type = NavType.StringType
defaultValue = JsonConverter.toJson(user, User::class.java)
},
)
)
}
Route sealed class:路由封class:
sealed class Route(val route: String) {
object MyRoute : Route("$ROOT/submit-form")
}
And in view model just get the data like this:在视图 model 中,只需获取如下数据:
@HiltViewModel
class MyViewModel @Inject constructor(
stateHandle: SavedStateHandle,
) : ViewModel {
lateinit var user
init {
user = stateHandle.get<String>(ARG_NAME) // Supported data types
}
}
It worked for me.它对我有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.