Jetpack Compose Navigation - 底部导航多个返回堆栈 - 查看模型范围问题
Posted
技术标签:
【中文标题】Jetpack Compose Navigation - 底部导航多个返回堆栈 - 查看模型范围问题【英文标题】:Jetpack Compose Navigation - Bottom Nav Multiple Back Stack - View Model Scoping Issue 【发布时间】:2021-11-24 03:01:11 【问题描述】:所以我有两个选项卡,选项卡 A 和选项卡 B。每个选项卡都有自己的后退堆栈。我使用google docs中的代码实现了多回栈导航
val navController = rememberNavController()
Scaffold(
bottomBar =
BottomNavigation
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
items.forEach screen ->
BottomNavigationItem(
icon = Icon(Icons.Filled.Favorite, contentDescription = null) ,
label = Text(stringResource(screen.resourceId)) ,
selected = currentDestination?.hierarchy?.any it.route == screen.route == true,
onClick =
navController.navigate(screen.route)
// Pop up to the start destination of the graph to
// avoid building up a large stack of destinations
// on the back stack as users select items
popUpTo(navController.graph.findStartDestination().id)
saveState = true
// Avoid multiple copies of the same destination when
// reselecting the same item
launchSingleTop = true
// Restore state when reselecting a previously selected item
restoreState = true
)
)
NavHost(navController, startDestination = A1.route)
composable(A1.route)
val viewModelA1 = hiltViewModel()
A1(viewModelA1)
composable(A2.route)
val viewModelA2 = hiltViewModel()
A2(viewModelA2)
composable(A3.route)
val viewModelA3 = hiltViewModel()
A3(viewModelA3)
选项卡 A 有 3 个屏幕(屏幕 A1 -> 屏幕 A2 -> 屏幕 A3)。我使用hiltViewModel()
函数来实例化视图模型,并在每个屏幕的composable()
块中调用它
问题是当我从 A1 导航到 A2 再到 A3 时,然后当我将选项卡更改为选项卡 B 时,屏幕 A2 的视图模型似乎正在被处理(调用onCleared
)。因此,当我返回显示屏幕 A3 的选项卡 A 然后返回屏幕 A2 时,再次实例化 A2 的视图模型(再次调用 init
块)。我想要实现的是为这个流程保留 A2 的视图模型,直到我退出 A2。
这可能吗?
【问题讨论】:
【参考方案1】:当您点击下一个导航项的速度过快,而当前视图显示转换尚未完成时,这似乎是一个错误。我已经reported了,请star一下,引起更多关注。
同时,您可以等待当前屏幕转换完成,然后再导航到下一个屏幕。为此,您可以检查 visibleEntries
变量并仅在它仅包含单个项目后导航。
另外,我认为当前文档提供的底部导航并不是最好的示例,因为如果您不在起始目的地屏幕上,按下后退按钮会将您带回到起始目的地,而我预计视图会被关闭.所以我也改变了你的导航方式,如果你对文档行为没问题,你可以用你自己的替换 fun navigate()
的内容。
val navController = rememberNavController()
var waitEndAnimationJob by remember mutableStateOf<Job?>(null)
Scaffold(
bottomBar =
BottomNavigation
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
val scope = rememberCoroutineScope()
items.forEach screen ->
fun navigate()
navController.navigate(screen.route)
val navigationRoutes = items
.map(Screen::route)
val firstBottomBarDestination = navController.backQueue
.firstOrNull navigationRoutes.contains(it.destination.route)
?.destination
// remove all navigation items from the stack
// so only the currently selected screen remains in the stack
if (firstBottomBarDestination != null)
popUpTo(firstBottomBarDestination.id)
inclusive = true
saveState = true
// Avoid multiple copies of the same destination when
// reselecting the same item
launchSingleTop = true
// Restore state when reselecting a previously selected item
restoreState = true
BottomNavigationItem(
icon = Icon(Icons.Filled.Favorite, contentDescription = null) ,
label = Text(stringResource(screen.resourceId)) ,
selected = currentDestination?.hierarchy?.any it.route == screen.route == true,
onClick =
// if we're already waiting for an other screen to start appearing
// we need to cancel that job
waitEndAnimationJob?.cancel()
if (navController.visibleEntries.value.count() > 1)
// if navController.visibleEntries has more than one item
// we need to wait animation to finish before starting next navigation
waitEndAnimationJob = scope.launch
navController.visibleEntries
.collect visibleEntries ->
if (visibleEntries.count() == 1)
navigate()
waitEndAnimationJob = null
cancel()
else
// otherwise we can navigate instantly
navigate()
)
) innerPadding ->
// ...
【讨论】:
【参考方案2】:找到了这个问题的根本原因。我正在使用这些依赖项,但它们似乎并没有结合在一起。
androidx.hilt:hilt-navigation-compose:1.0.0-alpha03
androidx.navigation:navigation-compose:2.4.0-alpha10"
我删除了 navigation:navigation-compose
依赖项,现在它似乎可以正常工作了。
【讨论】:
以上是关于Jetpack Compose Navigation - 底部导航多个返回堆栈 - 查看模型范围问题的主要内容,如果未能解决你的问题,请参考以下文章
Android Jetpack Compose学习—— Jetpack compose基础布局
Android Jetpack Compose学习—— Jetpack compose基础布局
Android Jetpack Compose学习—— Jetpack compose入门