Hi everyone, I have a question about the new navig...
# compose-android
y
Hi everyone, I have a question about the new navigation version. I updated my navigation to the last version of 2.8.1. After that, popBackStack(Destination. SpecificScreen(id = 12)) is not working. I changed my Destination object to class and set @Serializable annotation. I don't know what the problem is. Here, popBackStack() works fine but when I want to return a specific destination that is in the back stack that isn't working. Who has experience in these situations?
i
If you called
navigate(Destination.SpecificScreen(id = 12))
then
popBackStack(Destination.SpecificScreen(id = 12))
will work. Otherwise, you would not expect it to work. Is that how you navigated to that screen?
y
I tell you my case: I have 4 screen, and first is home and I navigate second screen with parameter. From second screen I navigate to the third then the fourth. From the fourth screen, I want to popBackStack to the second screen, but the second screen takes parameters. But even when I try to popBackStack to second screen with fake params, this is not working.
i
I'm not sure what you mean by fake params. It would need to match exactly if you are using the version that takes an instance of SpecificScreen
y
why we need to add params while poping back stack, for example I cannot carry parameters to any upcoming screens.
i
If you want to pop up to the topmost copy no matter what the params, you'd use the reified one
popBackStack<Destination.SecondScreen>()
👍 1
y
I didn't understand popBackStack how works, old version we didn't need parameters to return to the second screen from the fourth.
i
You don't need it now either
Instance = with params. <Class> = no params
y
How I use <Class>, I implemented navigation to my viewModels, every action comes to one navigation controller which is a listen channel for actions. In this controller class I get only intent, how can I do that? My controller:
Copy code
{
    val activity = (LocalContext.current as? Activity)
    LaunchedEffect(activity, navHostController, navigationChannel) {
        navigationChannel.receiveAsFlow().collect { intent ->
            if (activity?.isFinishing == true) return@collect

            when (intent) {
                is NavigationIntent.NavigateTo -> {
                    val curDestination = navHostController.currentDestination
                    Timber.i("WWW SS ${intent.route is Destination.Passcode}")
                    if (curDestination?.route?.contains("Passcode") == true) {
                        if (intent.route is Destination.Passcode) {
                            return@collect
                        }
                    }

                    navHostController.navigate(intent.route) {
                        launchSingleTop = intent.isSingleTop
                        //restoreState = true
                        intent.popUpToRoute?.let { popUpToRoute ->
                            popUpTo(popUpToRoute) { inclusive = intent.inclusive }
                        }
                    }
                }

                is NavigationIntent.NavigateBack -> {
                    Timber.i("www state=${navHostController.currentBackStackEntry?.lifecycle?.currentState}")
                    if (navHostController.currentBackStackEntry?.lifecycle?.currentState == Lifecycle.State.RESUMED) {
                        val route = intent.route
                        Timber.i("Lifecycle.State.RESUMED  route=${route}")
                        if (route == null) {
                            navHostController.popBackStack()
                        } else {
                            navHostController.popBackStack(route)
                        }
                    }
                }

                is NavigationIntent.ClearBackStack -> {
                    navHostController.navigate(Destination.Auth) {
                        this.popUpTo(0)
                    }
                }
            }
        }
    }
}
I try to popBackStack with this class:
Copy code
@Serializable
data class AddMerchantToHomeScreen(val id: Long = -1, val homeId: Long) : Destination
But it ends with an error. Can you give me links to any example or instructions? @Ian Lake
i
If you've forced yourself to always have instances of a class, then you probably want to use something like this if you want to ignore the parameters:
Copy code
if (route == null) {
    navHostController.popBackStack()
} else {
    // Pop until we get to the destination you want, comparing only the class
    while (navHostController.currentBackStackEntry?.destination?.hasRoute(route::class) == false)
        navHostController.popBackStack()
    }
    // Then if inclusive, pop one more time
    if (intent.inclusive) {
        navHostController.popBackStack()
    }
}
And if you say you got an error, you should really post the error message and the code you are using
y
This is a good solution, but if someone writes a destination that is not in backStack, this function ends the application. How do we handle that if this destination isn't available in backStack, then we stay on this screen.
Now our second problem like popBackStack problem above. While navigate to one screen, I want to set popUpToRoute, but this is again depending on parameters. Above, I sent codes of the navigation controller, how I set popUptoRoute without parameters?
Why I'm getting this warning?. My code works fine, but there is warning
i
Correct, only the reified versions are part of the public API right now, exposing the ones that that a KClass is going to be part of Navigation 2.9 and more specifically this bug: https://issuetracker.google.com/issues/363225480
y
So what should I do now to implement my logic? @Ian Lake
i
You can just suppress the warning
y
like that?
i
Yep
Then you'll be able to remove that suppression once you switch to the Nav 2.9 release that opens that API up
y
Thanks for helping.
Hi again @Ian Lake, I have a new error while popping back stack. While multiple fast-clicking navigateBack give me error:
Copy code
java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 1
                                                                                                    	at jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
                                                                                                    	at jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
                                                                                                    	at jdk.internal.util.Preconditions.checkIndex(Preconditions.java:266)
                                                                                                    	at java.util.Objects.checkIndex(Objects.java:359)
                                                                                                    	at java.util.ArrayList.get(ArrayList.java:434)
                                                                                                    	at V2.m$j.invokeSuspend(SourceFile:43)
                                                                                                    	at Y4.a.resumeWith(SourceFile:12)
                                                                                                    	at t5.b0.run(SourceFile:99)
                                                                                                    	at m1.B.performTrampolineDispatch(SourceFile:7)
                                                                                                    	at m1.B.access$performTrampolineDispatch(SourceFile:1)
                                                                                                    	at m1.B$d.run(SourceFile:3)
                                                                                                    	at android.os.Handler.handleCallback(Handler.java:958)
                                                                                                    	at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                    	at android.os.Looper.loopOnce(Looper.java:230)
                                                                                                    	at android.os.Looper.loop(Looper.java:319)
                                                                                                    	at android.app.ActivityThread.main(ActivityThread.java:9063)
                                                                                                    	at java.lang.reflect.Method.invoke(Native Method)
                                                                                                    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:588)
                                                                                                    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
                                                                                                    	Suppressed: y5.j: [m1.m0@903840f, A0.h@b55fc9c, W0{Cancelling}@33c46a5, B@6ce8a7a]
2024-11-13 10:25:04.793 19455-19481 ShellBackPreview        com.android.systemui                 E  Received BackNavigationInfo is null.
This is a my navigateBack logic:
Copy code
is NavigationIntent.NavigateBack -> {
    val backStackEntry = navHostController.currentBackStackEntry
    if (backStackEntry?.lifecycle?.currentState == Lifecycle.State.RESUMED) {
        val route = intent.route
        if (route == null) {
            popBackStack(navHostController, activity)
        } else {
            Timber.d("TTT popBackStacked with while")
            // Pop until we get to the destination you want, comparing only the class
            while (navHostController.currentBackStackEntry?.destination?.hasRoute(route::class) == false)
                popBackStack(navHostController, activity)

            // Then if inclusive, pop one more time
            if (intent.inclusive) {
                popBackStack(navHostController, activity)
            }
        }
    }
}