6

I have this scenario in which the user clicks on a button in composable A then selects an item from the list from composable B and selects another item from the list from composable C.

My problem is when I select an item from screen C I want to navigate back to screen A with whatever I selected in B & C. But popBackStack doesn't work when arguments are given.

Here is the code,

navController.popBackStack(route = Screen.SelectPlan.route + "?regionId=${region.id}&operatorId=${operator.id}")

Right now, I see that popBackStack does take a route argument, but converts it to a hashcode to navigate back instead of creating a Uri-like navigate function.

ash
  • 1,065
  • 1
  • 5
  • 20
nayan dhabarde
  • 1,734
  • 1
  • 19
  • 38
  • 1
    Are you using the **exact** `route` string you use when you created your `composable` destination? That's the route it is looking for – ianhanniballake Apr 21 '22 at 02:19
  • Does this answer your question? [Jetpack Compose navigate for result](https://stackoverflow.com/questions/66837132/jetpack-compose-navigate-for-result) – nglauber Apr 21 '22 at 03:33
  • @ianhanniballake **This is whats in the backQueue of NavController:** select_plan?operatorName={operatorName}&operatorId={operatorId}&regionName={regionName}&regionId={regionId} **This is what I am using for popBackStack route:** select_plan?operatorName=Jio&operatorId=0&regionName=Maharashtra & Goa (Incl. Nagpur)&regionId=13 – nayan dhabarde Apr 22 '22 at 15:30
  • 1
    I wonder if this is a bug in the SDK, basically popBackStack converts this to hashcode ```select_plan?operatorName=Jio&operatorId=0&regionName=Maharashtra & Goa (Incl. Nagpur)&regionId=13``` and treats this as an **id**, which definitely has to be different than the one generated from ```select_plan?operatorName={operatorName}&operatorId={operatorId}&regionName={regionName}&regionId={regionId}``` and thus is failed to find the destination by id – nayan dhabarde Apr 22 '22 at 15:45
  • Did you find a solution for this problem – Cyph3rCod3r Aug 03 '22 at 11:10

3 Answers3

2

I encountered the same issue and have just discovered the solution for myself.

When you navigate to a destination, using args like so:

val arg1 = "someValue"
val arg2 = "someOtherValue"
navController.navigate("Destination/$arg1/$arg2")

... this route is stored in the newly created backstack entry, not with the values of those args, but with their names as assigned in your NavHost.

Assume my NavHost contains a composable with a route of Destination/{arg1}/{arg2}.

If the .navigate() call in my previous example is executed, an entry will be added to the backstack with this route Destination/{arg1}/{arg2}, not this route Destination/someValue/someOtherValue.

You didn't provide your NavHost in the post, but if you replace the values of those args in the call to .popBackStack() with their names you assign in your NavHost, it should work for you.

Gigabyted
  • 33
  • 7
1

This is indeed a bug and it bothered me for a long time. After a long time of research and reading the navigation source code, I wrote my own extension function NavController.popBackStack to fix this problem. It is tricky but works for me. Also note that this version of extension function does not support the inclusive and saveState options (due to the current navigation API limitation), so you can't restoreState when you return to the current destination.

import android.content.Intent
import androidx.navigation.NavController

fun NavController.popBackStack(route: String): Boolean {
    if (backQueue.isEmpty()) {
        return false
    }

    var found = false
    var popCount = 0
    val iterator = backQueue.reversed().iterator()
    while (iterator.hasNext()) {
        val entry = iterator.next()
        popCount++
        val intent = entry
            .arguments
            ?.get("android-support-nav:controller:deepLinkIntent") as Intent?
        if (intent?.data?.toString() == "android-app://androidx.navigation/$route") {
            found = true
            break
        }
    }

    if (found) {
        navigate(route) {
            while (popCount-- > 0) {
                popBackStack()
            }
        }
    }
    return found
}
pfchen
  • 49
  • 2
0

Try put "/" instead of ?

 navController.popBackStack(route = Screen.SelectPlan.route + "/regionId=${region.id}&operatorId=${operator.id}")
Narek Hayrapetyan
  • 1,731
  • 15
  • 27