nayan dhabarde
nayan dhabarde

Reputation: 2346

Jetpack compose - How to do popBackStack with arguments?

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.

Upvotes: 10

Views: 6553

Answers (3)

Gigabyted
Gigabyted

Reputation: 63

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.

Upvotes: 5

pfchen
pfchen

Reputation: 97

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
}

Upvotes: 2

Narek Hayrapetyan
Narek Hayrapetyan

Reputation: 1929

Try put "/" instead of ?

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

Upvotes: 0

Related Questions