Jetpack Compose导航报错:无法匹配Recommendation/{recommendationId}目标
问题
我正尝试在应用中实现如下导航流程:
- 展示分类列表供用户选择
- 展示所选分类对应的推荐列表供用户选择
- 用户点击推荐项后展示该推荐的详情
分类列表和推荐列表功能正常,但点击推荐项时应用崩溃,抛出异常:
java.lang.IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{ uri=android-app://androidx.navigation/Recommendation/{recommendationId} } cannot be found in the navigation graph ComposeNavGraph(0x0) startDestination={Destination(0x6bf0b589) route=Categories}
相关代码:
sealed class MyCityScreen(val route: String) { object Categories: MyCityScreen("Categories") object Recommendations: MyCityScreen("Recommendations") object Recommendation: MyCityScreen("Recommendation/{recommendationId}") } @Composable fun MyCityApp( windowSize: WindowWidthSizeClass, navController: NavHostController = rememberNavController(), modifier: Modifier = Modifier ) { val viewModel: MyCityViewModel = viewModel() val myCityUiState = viewModel.uiState.collectAsState().value val backStackEntry by navController.currentBackStackEntryAsState() val contentType: MyCityContentType = when (windowSize) { WindowWidthSizeClass.Compact -> { MyCityContentType.LIST_ONLY } WindowWidthSizeClass.Medium -> { MyCityContentType.LIST_ONLY } WindowWidthSizeClass.Expanded -> { MyCityContentType.LIST_AND_DETAIL } else -> { MyCityContentType.LIST_ONLY } } if (contentType != MyCityContentType.LIST_AND_DETAIL) { NavHost( navController = navController, startDestination = MyCityScreen.Categories.route ) { composable(route = MyCityScreen.Categories.route) { val categories = myCityUiState.categories LazyColumn( modifier = Modifier .padding( end = dimensionResource(R.dimen.list_and_detail_list_padding_end), top = dimensionResource(R.dimen.list_and_detail_list_padding_top) ), verticalArrangement = Arrangement.spacedBy( dimensionResource(R.dimen.recommendation_list_padding) ) ) { items(categories, key = { category -> category.id }) { category -> MyCityCategoryListItem( category = category, selected = myCityUiState.currentSelectedRecommendation.id == category.id, onCardClick = { viewModel.updateRecommendations(category) navController.navigate(MyCityScreen.Recommendations.route) } ) } } } composable(route = MyCityScreen.Recommendations.route) { val recommendations = myCityUiState.currentRecommendations LazyColumn( modifier = Modifier .padding( end = dimensionResource(R.dimen.list_and_detail_list_padding_end), top = dimensionResource(R.dimen.list_and_detail_list_padding_top) ), verticalArrangement = Arrangement.spacedBy( dimensionResource(R.dimen.recommendation_list_padding) ) ) { items(recommendations, key = { recommendation -> recommendation.id }) { recommendation -> MyCityRecommendationListItem( recommendation = recommendation, selected = myCityUiState.currentSelectedRecommendation.id == recommendation.id, onCardClick = { navController.navigate( MyCityScreen.Recommendation.route ) } ) } } } composable( route = MyCityScreen.Recommendation.route, arguments = listOf(navArgument("recommendationId") { type = NavType.IntType }) ) { backStackEntry -> val recommendationId = backStackEntry.arguments?.getInt("recommendationId") val recommendation = myCityUiState.currentRecommendations[recommendationId!!] MyCityRecommendationDetailsCard( recommendation = recommendation, isFullScreen = false ) } } } else { MyCityHomeScreen( contentType = contentType, myCityUiState = myCityUiState, onCategoryCardPressed = { viewModel.updateDetailsScreenStates( category = myCityUiState.currentSelectedCategory, recommendation = myCityUiState.currentSelectedRecommendation ) }, onDetailScreenBackPressed = { viewModel.resetHomeScreenStates() }, onRecommendationCardPressed = { viewModel.updateDetailsScreenStates( category = myCityUiState.currentSelectedCategory, recommendation = myCityUiState.currentSelectedRecommendation ) } ) } }
我已定义路由object Recommendation: MyCityScreen("Recommendation/{recommendationId}"),并在NavHost中配置了对应的composable节点,为何导航仍找不到该目标?
原因与解决方案
核心问题
你调用navController.navigate(MyCityScreen.Recommendation.route)时,直接使用了包含占位符{recommendationId}的原始路由字符串,没有替换为实际的ID值。Navigation组件无法识别带有未替换占位符的路由,因此找不到对应的目标节点。
修复步骤
修改导航调用代码
在MyCityRecommendationListItem的onCardClick回调中,将占位符替换为当前推荐项的实际ID:onCardClick = { navController.navigate( MyCityScreen.Recommendation.route.replace("{recommendationId}", recommendation.id.toString()) ) }推荐优化:类型安全的路由生成
为避免手动替换占位符出错,可以给MyCityScreen.Recommendation添加一个生成带参数路由的方法:sealed class MyCityScreen(val route: String) { object Categories: MyCityScreen("Categories") object Recommendations: MyCityScreen("Recommendations") object Recommendation: MyCityScreen("Recommendation/{recommendationId}") { // 生成带实际ID的路由 fun createRoute(recommendationId: Int) = "Recommendation/$recommendationId" } }导航时直接调用这个方法:
onCardClick = { navController.navigate(MyCityScreen.Recommendation.createRoute(recommendation.id)) }额外优化:同步ViewModel状态
点击推荐项时,建议同时更新ViewModel中currentSelectedRecommendation的状态,确保详情页能正确获取数据:onCardClick = { viewModel.updateSelectedRecommendation(recommendation) navController.navigate(MyCityScreen.Recommendation.createRoute(recommendation.id)) }
修改后,Navigation组件就能正确识别导航目标,应用不会再崩溃。
内容的提问来源于stack exchange,提问作者Alexandru Gheorghe
相关产品推荐
相关产品推荐

