According to this example I implemented shared viewModels in a nested navigation graph.
Nested Graph:
private fun NavGraphBuilder.accountGraph(navController: NavHostController) {
navigation(
startDestination = "main",
route = "account") {
composable("main") {
val vm = hiltViewModel<AccountViewModel(navController.getBackStackEntry("account"))
//... ui ...
}
composable("login") {
val vm = hiltViewModel<AccountViewModel(navController.getBackStackEntry("account"))
//... ui ...
}
}
}
NavHost:
@Composable
private fun NavHost(navController: NavHostController, modifier: Modifier = Modifier){
NavHost(
navController = navController,
startDestination = MainScreen.Home.route,
modifier = modifier
) {
composable("home") { HomeScreen(hiltViewModel()) }
composable("otherRoute") { OtherScreen(hiltViewModel()) }
accountGraph(navController)
}
}
BottomNavBar:
@Composable
private fun ButtonNav(navController: NavHostController) {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
items.forEach { screen ->
BottomNavigationItem(
icon = { ... },
label = { ... },
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
navController.graph.startDestinationRoute?.let { route ->
popUpTo(route) { saveState = true }
}
// Avoid multiple copies of the same destination when
// re-selecting the same item
launchSingleTop = true
// Restore state when re-selecting a previously selected item
restoreState = true
}
}
)
}
}
}
With this setup if I naviagte to "account" (the nested graph) and back to any other route I get the error:
java.lang.IllegalArgumentException: No destination with route account is on the NavController's back stack. The current destination is Destination(0x78dd8526) route=otherRoute
BottomNavItem
The exception did not occure when I remove the popUpTo(route)
onClick. But then I ended up with a large stack.
lifecycle of backStackEntry
Have a look at the following:
//...
composable("main") { backStackEntry ->
val vm = hiltViewModel<AccountViewModel(navController.getBackStackEntry("account"))
//... ui ...
}
//...
I found out when navigating back the composable which will be left will be recomposed but in this case the backStackEntry seams to have another lifecycle.currentState
because if I wrap the whole composable like this:
//...
composable("main") { backStackEntry ->
if(backStackEntry.lifecycle.currentState == Lifecycle.State.RESUMED){
val vm = hiltViewModel<AccountViewModel(navController.getBackStackEntry("account"))
//... ui ...
}
}
//...
... the exception did not occure. The idea with the lifecycle issue came into my mind when I saw that the offical example has similar workarounds in place.
I actually do not know if I did something wrong or if I miss a conecept here. I can put the lifecycle-check-workaround into place but is this really as intended? Additional to that I did not find any hint in the doc regarding that.
Does anybody know how to fix that in a proper way?
Regards, Chris
There was an issue with the navigation component. It has been fixed for me with v2.4.0-alpha08
This is how you do it now but make sure you have the latest compose navigation artefacts:
private fun NavGraphBuilder.accountGraph(navController: NavHostController) {
navigation(
startDestination = "main",
route = "account") {
composable("main") {
val parentEntry = remember {
navController.getBackstackEntry("account")
}
val vm = hiltViewModel<AccountViewModel(parentEntry)
//... ui ...
}
composable("login") {
val parentEntry = remember {
navController.getBackstackEntry("account")
}
val vm = hiltViewModel<AccountViewModel(parentEntry)
//... ui ...
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.