Pie*_*ira 18 android android-jetpack-navigation android-jetpack-compose
我有一个用 jetpack compose 制作的应用程序,它工作得很好,直到我将 compose 导航库从版本2.4.0-alpha07升级到版本2.4.0-alpha08
在 alpha08 版本中,在我看来,该类arguments的属性NavBackStackEntry是 a val,所以它不能像我们在 2.4.0-alpha07 版本中那样重新分配。在2.4.0-alpha08版本中如何解决这个问题?
我的导航组件是这样的:
@Composable
private fun NavigationComponent(navController: NavHostController) {
NavHost(navController = navController, startDestination = "home") {
composable("home") { HomeScreen(navController) }
composable("details") {
val planet = navController
.previousBackStackEntry
?.arguments
?.getParcelable<Planet>("planet")
planet?.let {
DetailsScreen(it, navController)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试使导航发生在详细信息页面的部分是在这个函数中:
private fun navigateToPlanet(navController: NavHostController, planet: Planet) {
navController.currentBackStackEntry?.arguments = Bundle().apply {
putParcelable("planet", planet)
}
navController.navigate("details")
}
Run Code Online (Sandbox Code Playgroud)
我已经尝试过简单地应用到函数arguments的重复navigateToPlanet使用apply,但它不起作用,屏幕打开空白,没有任何信息。这是我失败的尝试的代码:
private fun navigateToPlanet(navController: NavHostController, planet: Planet) {
navController.currentBackStackEntry?.arguments?.apply {
putParcelable("planet", planet)
}
navController.navigate("details")
}
Run Code Online (Sandbox Code Playgroud)
ian*_*ake 33
根据导航文档:
注意:通过参数传递复杂的数据结构被认为是反模式。每个目的地应负责根据最少的必要信息(例如项目 ID)加载 UI 数据。这简化了流程重新创建并避免了潜在的数据不一致。
您根本不应该将 Parcelables 作为参数传递,并且从来都不是推荐的模式:在 Navigation 2.4.0-alpha07 和 Navigation 2.4.0-alpha08 中都没有。相反,您应该从单一事实来源读取数据。在您的情况下,这是您的Planet.data静态数组,但通常是存储库层,负责为您的应用程序加载数据。
这意味着您应该传递给您的DetailsScreen不是其Planet本身,而是定义如何检索该Planet对象的唯一键。在您的简单情况下,这可能只是所选行星的索引。
通过遵循参数导航指南,这意味着您的图表将如下所示:
@Composable
private fun NavigationComponent(navController: NavHostController) {
NavHost(navController = navController, startDestination = HOME) {
composable(HOME) { HomeScreen(navController) }
composable(
"$DETAILS/{index}",
arguments = listOf(navArgument("index") { type = NavType.IntType }
) { backStackEntry ->
val index = backStackEntry.arguments?.getInt("index") ?: 0
// Read from our single source of truth
// This means if that data later becomes *not* static, you'll
// be able to easily substitute this out for an observable
// data source
val planet = Planet.data[index]
DetailsScreen(planet, navController)
}
}
}
Run Code Online (Sandbox Code Playgroud)
根据Navigation Compose 的测试指南,您不应该NavController在层次结构中向下传递 - 此代码无法轻松测试,并且您无法用于@Preview预览可组合项。相反,您应该:
- 仅将解析后的参数传递到可组合项中
- 传递应由可组合项触发的 lambda 进行导航,而不是 NavController 本身。
所以你不应该把你的东西传递NavController给HomeScreen或DetailsScreen根本不应该。您可以首先在 中更改代码的用法,以提高代码的可测试性PlanetCard,这应该采用 lambda,而不是NavController:
@Composable
private fun PlanetCard(planet: Planet, onClick: () -> Unit) {
Card(
elevation = 4.dp,
shape = RoundedCornerShape(15.dp),
border = BorderStroke(
width = 2.dp,
color = Color(0x77f5f5f5),
),
modifier = Modifier
.fillMaxWidth()
.padding(5.dp)
.height(120.dp)
.clickable { onClick() }
) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
这意味着你PlanetList可以写成:
@Composable
private fun PlanetList(navController: NavHostController) {
LazyColumn {
itemsIndexed(Planet.data) { index, planet ->
PlanetCard(planet) {
// Here we pass the index of the selected item as an argument
navController.navigate("${MainActivity.DETAILS}/$index")
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以看到继续在层次结构中使用 lambda 将如何帮助封装您的MainActivity常量单独封装在该类中,而不是将它们分散到您的代码库中。
通过切换到使用索引,您可以避免创建第二个事实来源(您的参数本身),而是让自己编写可测试的代码,以支持静态数据集之外的进一步扩展。
Mah*_*eei 11
你可以传递这样的参数
val data = DestinationScreenArgument(title = "Hello")
navController.currentBackStackEntry?.savedStateHandle?.apply {
set("detailArgument", data)
}
navController.navigate(Screen.DetailScreen.route)
Run Code Online (Sandbox Code Playgroud)
并像这样在目的地中获取参数
val detailArgument = navController.previousBackStackEntry?.savedStateHandle?.get<DestinationScreenArgument>(
"detailArgument"
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
19053 次 |
| 最近记录: |