Is there a way when using navigation.compose to im...
# compose
s
Is there a way when using navigation.compose to imitate exactly what the back button would do? I want to basically run
navController::popBackStack
, but if the backstack is empty, then simply have it call
onBackPressedDispatcher.onBackPressed()
. Am I missing some sort of API that already exists? What is not working for me is that I launch an activity which has its own NavHost. When I am on the “top level” route of that activity, I have a TopAppBar which has the back button. When that back button is pressed, if we are at that empty backstack state, I want it to simply let the back press go to
onBackPressedDispatcher
so that it actually finishes the current activity. Now when I do
navController::popBackStack
it simply does nothing (and returns false as the result of popBackStack)
i
Navigation will never, ever finish your activity. If you ever support deep linking to that activity, you don't want to finish your activity there anyways (since that might drop users back to the launcher, rather than take them to the parent activity) - that's the key difference between the Up and Back button.
So what you actually want is
navController.navigateUp() || onSupportNavigateUp()
(if you are using AppCompatActivity, onNavigateUp otherwise)
s
Right, this does it! So basically this
navController.navigateUp() || onSupportNavigateUp()
should be specifically done for when one clicks on the top app bar, to follow the instructions from the docs here. Thanks a lot Ian 🤗
Hmm I do think I need to understand this better, but for my case what I actually had to do in the end was basically
navController.navigateUp() || onSupportNavigateUp() || finish()
inside my activity, since that was returning false and not exiting either, but I did in fact want it to finish my activity with the way everything is setup now. In a future where we won’t have all these activities I guess I can remove such stuff, but for now it is what it is,
i
It sounds like you didn't set a
parentActivityName
in your manifest, which is a requirement for the system to know what
onSupportNavigateUp
is supposed to do: https://stackoverflow.com/questions/19207762/must-i-specify-the-parent-activity-name-in-the-android-manifest
s
Hmm alright but in my situation my child activity is in a feature module which does not know about its parent activity, which in my case lives inside the base :app module, so I can’t directly reference it there. I guess I need to move my
<activity> ...
block in the :app module too instead of having it isolated in the child module so that it can reference it
Yeap this does seem to work. Even when it’s in the child module’s manifest and I use the correct name of the activity, even though it’s all red since it can’t reference it. I wonder if this means that I should just have all of my activities in my :app module anyway, and not define them in child modules since it blocks me from doing stuff like this. I think might as well just do that.
Aha! when doing navController.navigateUp(), if you are not currently in the startDestination then it will try to launch the activity again. This explains why as I describe here, this works fine with navigateUp() when I do this from the startdestination, while it does not work and tries to re-launch my current activity when I am on another destination which however I’ve made sure to be the only child in the backstack. If the start destination is not in the backstack at all, shouldn’t it also just fail this check and let me handle it myself by calling this@Activity.onSupportNavigateUp which I have now configured to target the activity I want it to? Now I am getting this very unwanted situation, due to the fact that I am popping out the startdestination before going to this other route of mine
I created this https://issuetracker.google.com/issues/271549886, maybe I am still misusing the APIs somehow, but let’s see if there’s someone else who has a better idea.
i
You should never be in a case where the start destination isn't on the back stack, as per the Principles of Navigation, unless you've deep linked into a specific destination on another app's task stack, which is what that navigateUp code is doing. It is intentional that the library assumes you've set up your graph correctly
s
Alright, I see where this comes from then. And again, thanks so much for bearing with me on this one, I really do appreciate the help! In my case, where I am in this incremental adoption stage, where I got this activity which has its own NavHost, I can’t really have this “fixed start destination” as far as I can tell. Specifically, in my use case I open this activity, which handles a specific flow, first you see some screens, which ask for some data, and at the end, you see a “result” sort of screen. At that point, if I go back, I specifically want to exit the entire flow, therefore what I’ve done right now was pop everything from the backstack, to have this “result” screen as the only destination in the backstack once the user has reached there. From what you say here I am going against the system, which makes sense. But what should be my start destination in this case? Any ideas? How else could I achieve this result in your opinion if it’s not by popping the entire backstack as I am doing?
i
Maybe your result screen should actually be a separate activity itself, so that you are actually finishing that flow by finishing that whole intermediate activity. (e.g., you go from Activity A -> Activity B (the one with your NavHost and the flow you've just completed) to Activity A -> Activity C (by calling finish() on B and starting Activity C to show your results)
s
Yeah maybe that is the case indeed. My entire goal with all this effort to introduce androidx.navigation in this codebase is to stop using activities, since now we basically got 100% activity-based navigation, so exploring ways to incrementally adopt it instead. So that’s why I’m trying my hardest not to introduce even more of them 😂 I’ll see if there’s anything else I can do before I do exactly what you say with the extra activity here. 🙏