I'm using `navigation` on a `compose desktop` app,...
# compose
p
I'm using
navigation
on a
compose desktop
app, and I have a main screen, which is the starting one, and it haves some loading data on the
init
block of his
viewmodel
. The problem is that when I navigate to another screen and then go to the main screen again, the
init
block of the main screen is again called, doing the loading again. How can this be avoided?
Copy code
NavHost(
    navController = appStateHolder.navController,
    startDestination = ScreenRoute.MainScreen.name,
    modifier = modifier
) {
    composable(ScreenRoute.MainScreen.name) {
        MainScreen(modifier = Modifier.padding(16.dp))
    }
    composable(ScreenRoute.StopsScreen.name) {
        StopsScreen(modifier = Modifier.padding(16.dp))
    }
    composable(ScreenRoute.LinesScreen.name) {
        LinesScreen(modifier = Modifier.padding(16.dp))
    }
}
To clarify, I'm navigating back to the main screen by calling
navController.navigate(ScreenRoute.MainScreen.name)
and not by pressing back, because back key is not present in
compose desktop
.
s
Call navController.popBackStack() instead of doing the navigation call which adds many copies of your main screen to your backstack
☝️ 1
☝🏼 1
p
I don't see that as a solution. Imagine the user do a more complex route like this: Main Screen -> Screen 2 -> Screen 3 -> Screen 4 -> Screen 2
how can I know that I must do a popbackstack to go from Screen 4 to Screen 2?
is not supposed that the navigation api must know it and do that pop back internally and automatically without letting the developer to manually know if it is on the stack and pop it manually?
like activities do in android
Imagine that my app haves 100 screens, I can't see as a solution to manually check on every navigation if the screen is in the stack and do a different call if so
that should be done automatically by navigation
doesn't exist a way to achieve it? to tell navController that when he receives a
navigate
call, if a screen is already on the stack, it must pop it instead of creating a new one?
s
Copy code
navController.popBackStack<ScreenRoute.MainScreen>(inclusive = false)
And your start destination must always be on your backstack, so this will always work.
NavOptions also give you the option to navigate to some destination while making sure it stays unique in your backstack and there are not many of them by using singleTop https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:navigati[…]igation/NavOptionsBuilder.android.kt;l=45?q=NavOptionsBuilder
Also while navigating, you can make sure to before doing the navigation call to pop the backstack up to some point, like
Copy code
navController.navigate(SomeScreen()) {
  popUpTo<SomeOtherScreen> {  
    inclusive = true
  }
}
You got control over all this, it's your choice what does or does not happen
p
ok, seems that that function is exactly what I'm searching for, so I did this:
Copy code
navController.navigate(route) { popUpTo(route) { inclusive = true } }
but it's not working, the init block of the viewmodel is still being called when going back to main screen using that function
but I can ensure is not working, or at least, if it's working, the init block of the viewmodel is still being called again when going back to main screen
s
How are you instantiating your ViewModel?
p
Copy code
vm: MainScreenViewModel = koinViewModel()
I think I found the solution
this works:
Copy code
if (!navController.popBackStack(route, inclusive = false)) {
    navController.navigate(route)
}
notice the
inclusive = false
if you put
inclusive = true
, it stops working, because it removes the destination from the backstack, and doing so, means that when you come back to it, it will be recreated from scratch recalling the init block of the viewmodel
if you use
navController.navigate(route) { popUpTo(route) { inclusive = false } }
it doesnt work, doesn't matter if you put true or false on inclsuive, didn't work in either case
I think that popUpTo removes the destination from the backstack even with inclusive = false
maybe it's a bug
what do you think?
s
If you navigate to ScreenA, while also doing popUpTo<ScreenA> { inclusive = false }, then you simply will have two instances of ScreenA in your backstack. Not a bug. That's why you see two ViewModels too. Print out your backstack information at that point to see what is happening.
p
why the behaviour is the same with popUpTo(route) { inclusive = false } and with popUpTo(route) { inclusive = true }?
in both cases, the init block of the viewmodel is called
but with this, not, with this works correctly:
Copy code
if (!navController.popBackStack(route, inclusive = false)) {
    navController.navigate(route)
}
if it's a feature to have the same behaviour with
popUpTo(route) { inclusive = false }
and with
popUpTo(route) { inclusive = true }
, I don't understand it
s
Did you print out your backstack to check if you have two instances of the same destination, and therefore two instances of your ViewModel?
It's not the same behavior whatsoever, one pops the route it finds one does not.
p
I'm checking this, Stylianos, and the backstack is increasing everytime even with this code:
Copy code
if (!navController.popBackStack(route, inclusive = false)) {
    navController.navigate(route)
}
and also I noticed that it doesn't recall main screen viewmodel init block if I come back from other screen... but if I press "main screen" button when staying in main screen, then, it recalls the init block
recap: these three doesn't work, recalls main screen viewmodel init block when coming back to main screen from other:
navController.navigate(route) { popUpTo(route) { inclusive = true } }
navController.navigate(route) { popUpTo(route) { inclusive = false} }
if (!navController.popBackStack(route, inclusive = true)) { navController.navigate(route)}
This one doesn't call the init block in that case, but it does when I'm on main and press go to main button and also, increases constantly backstack
if (!navController.popBackStack(route, inclusive = false)) { navController.navigate(route)}
do you know a complete solution for this issue?