https://kotlinlang.org logo
#compose-android
Title
# compose-android
a

Almeric

10/30/2023, 7:52 AM
I’m having some issues with navigation in compose and I’m wondering if it’s expected behaviour… I have a bottom navigation bar with two top-level destinations (A and C) A is a nested navigation graph which also contains destination B. If I navigate A -> B, then click on the bottom nav item to go to C and then click on the first bottom nav item I’m back at B (as expected). But if I go back using the system navigation I return to A, but I expected to return to B (as that’s the current ‘active’ item in A’s graph). More info in thread
This is my NavHost:
Copy code
NavHost(
    modifier = Modifier.padding(it),
    navController = appState.navController,
    startDestination = "homeGraph"
) {
    navigation(
        startDestination = "home",
        route = "homeGraph"
    ) {
        composable("home") {
            Home("A") {
                appState.navController.navigate("home2", null)
            }

        }
        composable("home2") {
            Greeting("B")
        }
    }
    composable("settings") {
        Greeting("C")
    }
}
Navigating to top level destinations is done as follows:
Copy code
fun navigateToTopLevelDestination(topLevelDestination: TopLevelDestination) {
    val topLevelNavOptions = navOptions {
        popUpTo(navController.graph.findStartDestination().id) {
            saveState = true
        }
        launchSingleTop = true
        restoreState = true
    }
    when (topLevelDestination) {
        TopLevelDestination.HOME -> navController.navigate("homeGraph", topLevelNavOptions)
        TopLevelDestination.SETTINGS -> navController.navigate("settings", topLevelNavOptions)
    }
}
And here’s a recording of the issue:
I expected to return to B when swiping back from C. Am I wrong in my assumption, or is there something I’m doing wrong? Thanks!
s

Stylianos Gakis

10/30/2023, 9:07 AM
Hmm, I am not sure what the navigation principles say for this one, but it does make sense that B is not also restored, since you only pop the backstack, you don’t also explicitly ask for it to restore the state right? From that perspective it makes sense I would say.
a

Almeric

10/30/2023, 11:03 AM
The weird part is that after I use the system back from C I go to A, but if I then click on the first item in the bottom navbar (which is already active) I’m back on B. I can imagine that’s confusing from a users’ perspective.
s

Stylianos Gakis

10/30/2023, 11:20 AM
Not necessarily. There’s two things at play here: • Clicking at the bottom nav to go somewhere, is connected with also remembering where you were in that tab previously and restoring it accordingly • When you are at the root of C, going back you expect to go back to the start destination of the app, where another back will then make you exit the app. I think the navigation principles really put a lot of emphasis on getting predictable and consistent behavior when going back from the root of a bottom nav bar destination. And this may be more important than point #1. I don’t know what your UI in the real app really looks like, but for us when you are in A, if we navigate somewhere from there which is not a top level destination, then the bottom nav is hidden, so that interaction can never happen when you are in A -> B and then you go to a top level destination after saving state. If this is not the case for you, not sure if there’s something to be done here. Sorry for the ping, but this in general is an interesting question for navigation I think @Ian Lake. Is this specified anywhere in the docs? Because I haven’t found anything myself.
a

ascii

10/30/2023, 11:23 AM
Start destination is key here. If you set
startDestination = "home2"
you'll see that pressing back from C will always open B.
I don't know if there's a way to remember nested destinations when going back, other than mutating startDestination via remember + mutableStateOf.
s

Stylianos Gakis

10/30/2023, 11:30 AM
If you set
startDestination = "home2"
you’ll see that pressing back from C will always open B.
Then you are breaking the entire graph, why would they want to change the entire start destination for this?
other than mutating startDestination via remember + mutableStateOf
That to me sounds like a bad idea. If you do that, then if you are in B and you want to do the back gesture, then what, would you exit the app directly from “home2"? If that’s the start destination you’d also want it to be the beginning of the backstack, so as you try to go back you’ll see the back gesture exiting the app and then you’d actually exit the app, no?
a

ascii

10/30/2023, 11:52 AM
why would they want to change the entire start destination for this?
Just an example to help them understand
i

Ian Lake

10/30/2023, 2:00 PM
You said
popUpTo(navController.graph.findSta rtDestination().id)
so the only thing left on the back stack (e.g., what happens when you do system back) is the start destination of the graph, so what you're seeing is exactly what you said you wanted to see.
gratitude thank you 1
That aligns with the expectation here: users shouldn't be popping back through many back stacks (e.g., no stack for tab c or stack for tab a either) - once they finish the stack on tab b, they see the start destination (their signal that the next back press will take them out of the app), then the next system back takes them out of the app.
d

dorche

10/30/2023, 11:19 PM
On that last bit "they see the start destination (their signal that the next back press will take them out of the app)" - is that the start destination of the inner graphs? Does that assume that the start destination is not one of the bottom nav items itself?
i

Ian Lake

10/30/2023, 11:31 PM
If you say
popUpTo(navController.graph.findStartDestination().id)
, that is the start destination of your entire graph. It is actually assumed that it is part of your bottom nav, not the opposite, but that's more of a convention than requirement
a

Almeric

10/31/2023, 7:47 AM
Thanks for looking in to this everyone! So in short I’d say it’s expected behaviour. I hoped that by using
saveState = true
in the
PopupToBuilder
this would also restore the state when popping ‘back’ to this destination.
2 Views