When I open the app from a deeplink (user clicks on URL) and press back button I expect user to navigate to a previous fragment in my navigation graph but it just exits the app.
The documentation says that back navigation should work the same way as if it the user got to that screen naturally.
Can I somehow specify the desired backstack in my navigation graph? Or can be backstack formed automatically after a deeplink? For older version of the library I found out that after back press it should navigate to the root of my navigation graph but that does not happen.
I’m using the navigation library from Android architecture components (version 1.0.0-beta01).
I found out what's going on here, for explicit deep links its supposed to go to a new back stack which is what you app would have if a user had naturally navigated to the view not the existing back stack (existing stack is cleared.
When a user opens your app via an explicit deep link, the task back stack is cleared and replaced with the deep link destination. When nesting graphs, the start destination from each level of nesting—that is, the start destination from each element in the hierarchy—is also added to the stack. This means that when a user presses the Back button from a deep link destination, they navigate back up the navigation stack just as though they entered your app from its entry point.
For implicit its a bit strange. You can make it do what explicit does but setting Intent.FLAG_ACTIVITY_NEW_TASK otherwise the back button and the navigation up button do two separate things:
The back button will do as you might expect, it will go back in your apps existing back stack and load that fragment.
The up button however will clear the a back stack and make a new one as if it was an explicit link.
If the flag is not set, you remain on the task stack of the previous app where the implicit deep link was triggered. In this case, the Back button takes you back to the previous app, while the Up button starts your app's task on the hierarchical parent destination within your navigation graph.kquote
Source: Android Documentation
As describe here back button should return to the previous fragment, you can set it manually in Java like this: button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null));
In Kotlin like that: button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null))
The Android system maintains a back stack containing the last visited destination. The first destination of your app is placed on the stack when the user opens the app. Each call to the navigate() method puts another destination on the top of the stack. Conversely, pressing the Up or Back button calls the NavController.navigateUp() and NavController.popBackStack() methods, respectively, to pop the top destination off of the stack.
Make sure that you are using NavHostFragment and not <fragment> in your hosting fragment activity.
Related
I am implementing a login system with Jetpack Compose and I'm using Compose Navigation. I have an "onboarding" screen where the user can choose whether they want to login or sign up. Fromn both the login and sign up screen the user can navigate to the other one, but let's say they keep navigating back and forth, then the back stack is full of those screens.
How should I handle the back stack in this case? I thought about checking if the destination is already present in the back stack and pop to that, but it looks like this has some pitfalls (the user could have visited one of those pages before and pop several destinations for example).
I'd also like to pop the whole login flow when done but I don't get how
How should I handle the back stack in this case? I thought about
checking if the destination is already present in the back stack and
pop to that
In a way you're right, but you don't need to do much of it yourself if you have circular navigation (this is what you describe). You can just use popUpTo from the signup page (if the login is supposed to be the "default" like such:
navController.navigate(loginRoute) {
popUpTo(loginRoute) {
inclusive = true
}
}
The inclusive = true is necessary because you also want to pop the login from the stack itself:
If your stack looks like AB and you navigate back to A, you would pop just B and be left with AA (thus able to navigate back to A again while you're at A).
I'd also like to pop the whole login flow when done but I don't get how
Similar to your initial idea, just pop the entire backstack after you're done using navController.navigate(yourRoute) { popUpTo(0) }
I am making A Trivia app following Udacity Android with Kotlin guide.
In Navigation Graph there are three destination screen; TitleFragment, GameFragment,GameOverFragment and GameWonFragment. (Images for code are included)
While constructing Navigation graph, we are setting up for system back key by setting popUpTo behavior attribute.
The guide says us to setup popUpTo (inclusive) attribute for action connecting GameFragment to GameOverFragment and GameWonFragment which will lead back to TitleFragment by popping up fragments including GameFragment on system back button hit. I understood till here.
But again the guide tells us to set action tag and popUpTo attribute from GameOverFragment and GameWonFragment to GameFragment. This time we wet popUpTo attribute(exclusive) for popping upto TitleFragment on system back key hit.
Both set up are doing same thing; taking us to TitleFragment on System back key hit. So, why setting up 2 times is necessary?
As the Documentation say :
When navigating using an action, you can optionally pop additional
destinations off of the back stack. For example, if your app has an
initial login flow, once a user has logged in, you should pop all of
the login-related destinations off of the back stack so that the Back
button doesn't take users back into the login flow.
To pop destinations when navigating from one destination to another,
add an app:popUpTo attribute to the associated element.
app:popUpTo tells the Navigation library to pop some destinations off
of the back stack as part of the call to navigate(). The attribute
value is the ID of the most recent destination that should remain on
the stack.
You can also include app:popUpToInclusive="true" to indicate that the
destination specified in app:popUpTo should also be removed from the
back stack.
When using popUpTo , all destinations from current destination to the destination with the id in popUpTo will be deleted , except that destination with id which will remain in the back stack .
And when using popUpToInclusive = true , then all destination and also the destination with the id in popUpTo will be deleted from the back stack !
This is more clear explain in detail about this , in the official documentation .
Enjoy !
im currently working on an app, and i want to be able to share images to my app.
with multiple activities this doesn't seem to be a problem, since you define your activity as intent receiver.
however how would i do this, with the single activity architecture google is pushing with its navigation api ?
should the single main activity handle it or does it make sense to create a second activity in this scenario.
i couldn't really find anything on that topic in the android dev docs
Pass Uri to your navController instead of navigating manually by fragment id.
val deeplink = Uri.parse("android-app://androidx.navigation.app/yourFragmentId")
findNavController().navigate(deeplink)
Unlike navigation using action or destination IDs, you can navigate to any URI in your graph, regardless of whether the destination is visible. You can navigate to a destination on the current graph or a destination on a completely different graph.
When navigating using URI, the back stack is not reset. This is unlike other deep link navigation, where the back stack is replaced when navigating. popUpTo and popUpToInclusive, however, still remove destinations from the back stack just as though you had navigated using an ID.
I have a nav structure like so:
StaringFragment -> nestedNavGraph
|
HomeFragment -> SecondFragment
I need to make it so that after the user navigates away from StartingFragment to the nestedNavGraph the user can no longer hit the back button to return to the StartingFragment.
I am basically performing a permissions check, and if the check succeeds I navigate from the StartingFragment to the nestedNavGraph with this code:
findNavController(R.id.nav_host_frag).navigate(R.id.nestedNavGraph)
Then, on the action arrow between the StartingFrag -> nestedNavGraph in the nav graph editor, I set popUpTo to HomeFragment and inclusive to true. Did I misunderstand the documentation?
What's the proper way to remove the StartingFragment from the backstack as soon as I navigate away from it?
As per the documentation, you set app:popUpTo to the destination you want to pop - you don't want to pop the HomeFragment, you want to pop the StartingFragment, so you should set your app:popUpTo to the ID of the StartingFragment.
Note that as per the Principles of Navigation, you should always have a fixed starting destination - you shouldn't be using the start destination for conditional navigation - many of the APIs in Navigation, such as NavigationUI, assume you're correctly following the Principles of Navigation and that the start destination of your graph remains on your back stack.
Keep in mind that Android will restore your state (including what fragment you were at) when returning to your activity (say, after the user manually revoked the permissions you asked for) - your Fragment itself (or the activity if the permission really is globally required on every single screen in your whole app) should always be checking for permission - you can't rely on your StartingFragment always being called.
I haven't used the nav lib yet, but from reading this bit in the documentation maybe you just have a typo and need to replace popTo with popUpTo?
To pop destinations when navigating from one destination to another, add a app:popUpTo attribute to the associated element. app:popUpTo tells the Navigation library to pop some destinations off of the back stack as part of the call to navigate(). The attribute value is the ID of the most recent destination that should remain on the stack.
You can also include app:popUpToInclusive="true" to indicate that the destination specified in app:popUpTo should also be removed from the back stack.
I'm currently using Android Navigation Architecture in my project. It has a feature that can launch any fragment with a shortcut.
Suppose my navigation graph looks like this: A->B->C->D.
When I'm at fragment A , I directly navigate to fragment D with NavController.navigate(R.id.fragment_d). But when I'm press back button, it returns to fragment A. Is there any way to let the destination navigate back to its parent in navigation graph? (I mean, in this case, D back to C, B then back to A).
Thanks in advance.
Generally, you should always avoid creating a synthetic back stack when within your own app (and only do this when launching your app from a deep link outside your app, i.e., via an app shortcut).
However, you can approach this in one of two ways:
If you're okay with resetting the state on A, you can use NavDeepLinkBuilder to construct a set of Intents suitable for restarting your task on the chosen destination:
navController.createDeepLink()
.setDestination(R.id.destination_d)
.createTaskStackBuilder()
.startActivites()
Just call navigate() multiple times.
navController.navigate(R.id.destination_b)
navController.navigate(R.id.destination_c)
navController.navigate(R.id.destination_d)
I think you should be able to use navControler.navigateUp() on the destination if you have correctly introduced the parent fragment for your fragments. Also, consider the difference between the device back button and up back-arrow to go up to the parent