I have a problem with compose navigation. Is it co...
# compose
e
I have a problem with compose navigation. Is it correct behavior if we navigate to a route with setting restore and save state flag to true and it doesn't work?? (Even navigation itself) https://github.com/erfansn/ComposableScreens/blob/master/food/kristina_cookie/src/[…]posablescreens/food/kristina_cookie/KristinaCookieNavigation.kt #C0B8M7BUY #C1FLMRTJA
s
Not sure what exactly you mean by "it doesn't work (even navigation itself)". But in any case, are you following the docs here? https://developer.android.com/develop/ui/compose/navigation#nested-nav They got a snippet of how to do this here:
Copy code
onClick = {
    navController.navigate(topLevelRoute.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
    }
}
If you see no navigation at all happening, is there a chance you are navigating somewhere, but you
restoreState = true
, so the restoration just restores the backstack to exactly what it is before you do anything, so you just see nothing going on as a result?
e
I am developing this project and I encountered this problem. This is the nav graph of my project.

https://github.com/erfansn/ComposableScreens/blob/master/food/kristina_cookie/media/ComposableScreens_FoodGraph.png

In this part of the code, instead of using the single Top launch, I first said that the pop operation was done along with saving the state until the home path, and then the restore operation was done after entering the home, but it didn't work at all.
Copy code
navController.navigate(HomeRoute) {
    popUpTo(HomeRoute) {
}
https://github.com/erfansn/ComposableScreens/blob/65ba11421fa71bce7eb38b3d5c8ca691[…]posablescreens/food/kristina_cookie/KristinaCookieNavigation.kt
Also, I noticed that the state recovery operation occurs on the argument, which I think should not be. Consider my real example. This is the image of the navigation graph of the module. I go from the home page to a product page and from there to the cart page and enter the product page from the list provided to me. The problem is here. I need to restore the internal state in the product page that was saved by rememberSaveable, but the problem is here. The product id is included in the recovery process and the information of the selected product from the cart is not displayed. I commented the code related to state storage so that I don't see incorrect behavior. https://github.com/erfansn/ComposableScreens/blob/master/food/kristina_cookie/src/[…]posablescreens/food/kristina_cookie/KristinaCookieNavigation.kt
s
So you go:
Home -> Product -> Cart -> Product (again)
correct? Because if that is the case, I am not sure I understand why you want to restore any state when going to product. It is a new entry to the backstack and should be on top of everything right? If you then press the back button 3 times, do you expect to see this? Product (you are here after the flow you described) -> Cart -> Product (the first product you saw) -> Home
i
Copy code
navController.navigate(HomeRoute) {
    restoreState = true
    popUpTo(HomeRoute) {
       saveState = true
    }
}
is equivalent to
Copy code
// Pop everything up to HomeRoute
// Saving the state so that the next time
// you navigate to HomeRoute with restoreState = true
// that state is restored
navController.popBackStack(HomeRoute, inclusive = false, saveState = true)
// Navigate to HomeRoute, restoring the state that
// was saved on it
navController.navigate(HomeRoute) { restoreState = true)
Of course that isn't doing anything. You're restoring what you just saved, putting you exactly back where you were.
e
So sorry I'm forgot about inclusive in popUp dsl:
Copy code
navController.navigate(HomeRoute) {
    restoreState = true
    popUpTo(HomeRoute) {
       inclusive = true
       saveState = true
    }
}
@Ian Lake This operation will be performed with the back stack of Home->Product->Cart when the user presses the back button.
s
You navigate to Home route, and you pop to HomeRoute as you do so? Is what you're looking perhaps just to pop everything until you find the first HomeRoute in your backstack? I am having a very hard time understanding what you want to do here.
i
You must not do anything custom when system back is pressed, since that means you've already completely broken Predictive Back. You'll want to make sure your back stack is already correct when you go to a page such that system back takes you to where you need automatically
e
State saving and restoration problem: I have an animation in the
Product
screen that I only want to run when navigating to it from the
Home
screen and when returning to it. To achieve this, I used
rememberSaveable
to keep a flag in the backstack and restore it to decide whether or not to run the animation. The issue is that when I enable the save-and-restore mechanism, the arguments passed to the
Product
screen are also included in the save-and-restore process, which causes issues. Let me explain with an example to clarify. Suppose in the
Cart
, products with IDs 2 and 3 already exist, and I want to add another product with ID 1. Example flow: 1.
Home -> Product(1)
– (Check the flag; since it’s “false,” run the animation, add the product to the cart, set the flag to “true,” and navigate to the
Cart
while popping
Product(1)
from the stack with state saving.) 2.
Cart -> Product(2)
– (Navigate to
Product(2)
with state restoring, check the flag, and since it’s “true,” don’t run the animation.) 3.
Product(1)
I expected Product(2) but Product(1) delivered to me!!!!!!!! (Argument values in state save/restoration)
@Stylianos Gakis For the no navigation issue: In short, on one of my screens, I have a button that is supposed to take me back to the
Home
screen. I’m using the following code for this, but when I tap the button, nothing happens:
Copy code
navController.navigate(HomeRoute) {
    restoreState = true
    popUpTo(HomeRoute) {
       inclusive = true
       saveState = true
    }
}
@Ian Lake Yes, you’re right, but I didn’t mean the system back button; it’s just a button in the app’s UI.
s
You got your answer for the "nothing happens" question here https://kotlinlang.slack.com/archives/CJLTWPH7S/p1729885743389849?thread_ts=1729882860.379189&cid=CJLTWPH7S Restoring state also restores the navigation state of that graph.
e
I still don’t understand why, when I’m on the
Cart
screen and execute this code, it doesn’t navigate back to the
Home
screen.
s
You navigate to the Home graph, and you restore the state of the graph. The graph before had Cart on top of Home, so you see Cart again It's the entire reason why navigation with nested backstacks works, as you navigate between the graphs you get back to where you were, instead of navigating always to the "top level" destination and losing the entire nested backstack. https://developer.android.com/guide/navigation/backstack/multi-back-stacks
1
i
This seems like an XY Problem: https://en.m.wikipedia.org/wiki/XY_problem If your problem X is you only want to run an Animation on the Product screen when coming from the Home screen, asking why saveState/restoreState isn't working is the wrong problem Y to be asking about. There's never, ever going to be any
rememberSaveable
state shared between Product(1) and Product(2) - that's not the right problem to be focused on
👍 1
Instead, if your problem is the animation from the Home to the Product screen and avoiding that same animation from the Cart to Product screen, let's focus on that. Something as simple as checking
navController.previousBackStackEntry?.destination?.hasRoute<Home>()
as the conditional for starting your animation in Product might be enough without any of the rest of this
good idea 1
e
@Ian Lake I also felt that I hadn’t asked my questions clearly and made things more complicated by mixing in my own issue. I had two main objectives with these questions: 1. Is this a bug in the navigation library? 2. Why doesn’t the code I wrote behave as expected? Let me rephrase my questions more simply: Firstly, when we save and restore state, what happens under the hood? Is a version of the backstack copied and then later restored? I’m asking to understand why the following code doesn’t work when I try to navigate from the
Cart
screen to `Home`:
Copy code
navController.navigate(HomeRoute) {
    restoreState = true
    popUpTo(HomeRoute) {
       inclusive = true
       saveState = true
    }
}
Secondly, are the arguments provided for navigating to a specific route also included in the save process? If so, how can I prevent this?
i
You save the entire back stack, including all of its state (and yes, arguments are part of the identity of each entry and unchangeable), then you restore that back stack exactly as it was
e
@Ian Lake @Stylianos Gakis thank you so much