我们的项目正在使用 jetpact 撰写和导航组件。
我们有 2 个片段 - 片段 A 和 B 。在片段 A 中,由于存在多个元素(例如 View Pager 和惰性列),UI 有点复杂。惰性列根据 viewpager 选择进行更新。从 Fragmnt A 的惰性列中选择一个项目时,它将导航到 Fragment B 。我们目前正在使用 Android 导航组件。问题是导航组件将进行片段替换。当片段 B 的 onbackpress 被调用时,它将重新创建片段 A。因此,我们会丢失片段 A 的 UI 状态。我们无法将片段 B 作为对话框目标,因为当从片段 B 打开片段 C 时,它应该位于堆栈中。
我们找到了 3 个解决方案,但都遇到了一些问题。
在 ViewModel 中保存 UI 状态并在重新创建 Fragment A 时恢复状态。
-- 我们可以在ViewModel中保存Viewpager的UI状态。但是保存列表滚动状态将不起作用,因为列表将在 viewpager 状态更新后刷新。这种方法再次进行视图重建,这会在从片段 B 按下时造成性能延迟
将fragment Replace替换为Fragment Add后提供CustomFragmentNavigator。
-- 这将引入更多样板代码,我们认为这是一种反模式,因为谷歌有意在导航中进行了片段替换。
在片段 A 中执行较旧的 Frgament 事务,而不是使用导航组件。当需要使用较旧的片段事务或使用导航组件添加片段时,请使用混合方法。
-- 由于我们使用 navhostfragment ,无法获取容器 ID 来执行正常的fragment事务。我们在根布局中只有容器片段。
期待有关此问题的一些技术指导。应该用什么方法来解决这个根本问题。
根据文档:
当您使用
导航到目的地时,您可以选择 保存从后堆栈弹出的所有目的地的状态。popUpTo
要启用此选项,请在关联操作中将
定义为popUpToSaveState
,或调用true
。NavController.navigate()
当您导航到目的地时,您还可以将
定义为restoreSaveState
,以自动恢复与目的地属性中的目的地相关联的状态。true
XML 示例
<action
android:id="@+id/action_a_to_b"
app:destination="@id/b"
app:popUpTo="@+id/a"
app:popUpToInclusive="true"
app:restoreState=”true”
app:popUpToSaveState="true"/>
撰写示例
@Composable
fun MyAppNavHost(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
startDestination: String = "destination_a"
) {
NavHost(
modifier = modifier,
navController = navController,
startDestination = startDestination
) {
composable("destination_a") {
DestinationA(
onNavigateToB = {
// Pop everything up to the "destination_a" destination off the back stack before
// navigating to the "destination_b" destination
navController.navigate("destination_b") {
popUpTo("destination_a") {
inclusive = true
saveState = true
}
}
},
)
}
composable("destination_b") { DestinationB(/* ... */) }
}
}
@ Composable
fun DestinationA(onNavigateToB: () -> Unit) {
Button(onClick = onNavigateToB) {
Text("Go to A")
}
}
更具体地说,您可以通过以下方式更改您的通话方式
NavController.navigate()
:
// Pop everything up to the destination_a destination off the back stack before
// navigating to the "destination_b" destination
navController.navigate("destination_b") {
popUpTo("destination_a")
}
// Pop everything up to and including the "destination_a" destination off
// the back stack before navigating to the "destination_b" destination
navController.navigate("destination_b") {
popUpTo("destination_a") { inclusive = true }
}
// Navigate to the "search” destination only if we’re not already on
// the "search" destination, avoiding multiple copies on the top of the
// back stack
navController.navigate("search") {
launchSingleTop = true
}
请参阅此链接了解更多信息: 导航和返回堆栈