I have multi module android App, so I have a question regarding back stack with deep link.
For example we can manage and clear back stack with setPopUpTo method in jetpack navigation.
Like home -> notification -> about
So If I need to back to home from about and clear notification screen between in back stack I can use in notification to about navigation:
val navOption = NavOptions.Builder().setPopUpTo(R.id.home_nav, false).build()
findNavController().navigate(dest,null, navOption)
So on back press I back to home directly and skip the notification route from back stack.
But in second case when I go from notification (feature home) to product detail (feature product) directly with the help of deep link like:
<fragment
android:id="#+id/productDetailFragment"
android:name="com.gymat.gym.domain.modules.courts.views.ProductDetailFragment"
android:label="productDetailFragment"
tools:layout="#layout/fragment_product_detail">
<argument
android:name="param_id"
android:defaultValue="default"/>
<deepLink
app:uri="myApp://productDetailFragment/{param_id}" />
</fragment>
And in notification I can route to product detail directly with the help of URI like this:
val uri = Uri.parse("myApp://productDetailFragment/2bb6e920-032c-4829-8801-cfe3fb787c36")
findNavController().navigate(uri)
In this way I can go to another graph child fragment directly with the help of deep link. So I stuck in a case when user come back from checkout to notification directly.
So here I have two cases:
first case when user go to checkout and press back the same product detail screen will show from back stack, but if user checout successsully I have to go back to notification screen directly from checkput. But in feature product we do not have access to other graph child fragment, So any idea about how I can set setPopUpTo to notification directly from checkout screen.
Related
I navigate to a destination using deep link in another navigation graph
Navigation.findNavController(view).navigate(Uri.parse(link));
And I just want to return to the previous destination.
However, popBackStack() only restart the deep link destination
Navigation.findNavController(view).popBackStack();
How can I return to the previous destination if I insist to use deep link?
Check this. It might help. https://developer.android.com/guide/navigation/navigation-deep-link#explicit
the start destination of the graph also added to the stack. So when you click on the back button, the start destination on the graph coming to the top of the stack.
My goal: I want to send push notification to users. When user tap on that notification, user should navigate to a specific fragment named HitoryDetailsFragment.
What I did: I implemented FirebaseInstanceIdService & FirebaseMessagingService and I'm able to catch Firebase message which is sent from a backend server. I implemented the deep link by an "implicit deeplink". I implemented the navigation using nested navigation graphs. History related screens are placed in a separate navigation graph, graph_history.xml.
What is the issue: When the application is open, everything works fine. I tap on the notification -> I get redirected to HistoryDetailFragment, and when I press the back button, it returns me to the HistoryListFragment. But when the app is closed (not in the recent apps tray), instead of HistoryDetailsFragment, the SplashFragment is opened, and after that I get redirected to the HomeFragment (which is correct, because that's how the flow should work). But, how can I redirect the user to the HistoryDetails, when the app is closed? Also, I should show a Pin screen, where the user should input his pin, if he did not before, before showing the HistoryDetailsFragment.
My code is like below.
private fun createPendingIntent(history: History?) = NavDeepLinkBuilder(this).run {
setGraph(R.navigation.graph_main)
history?.let {
//todo when the app is not open (not in tray of recent apps), this destination does not work
//this instead navigates to SplashFragment
//which is correct, because we have not entered the pin, so we are not entitled to open the history detail screen
//but how do I handle this case?
setDestination(if (it.type.isNews) R.id.nav_history_news else R.id.nav_history_detail)
setArguments(if (it.type.isNews) HistoryNewsFragmentArgs(it.link).toBundle() else HistoryDetailFragmentArgs(it.id).toBundle())
}
createPendingIntent()
}
The main nav graph:
History graph:
Today I've started playing with Android's Navigation Component to implement authentication flow in my app. The idea is very simple: a user launches the app and it displays one piece of UI if she's authenticated and another if she's not.
What I've done is in my HomeFragment's onViewCreated method I check if a user is authenticated and if she's not I call the NavController's navigate() method by passing it the id of an action that will navigate to the AuthenticationFragment. Everything works fine until a user clicks the back button while in AuthenticationFragment, because then I get this error. I still have no idea what's the actual reason for that error, but the idea of navigation happening too quickly seems similar to my case: the destinations first switch from AuthenticationFragment to HomeFragment and then immediately from HomeFragment to AuthenticationFragment again, because HomeFragment finds out again that a user is not authenticated.
Despite of the error I'm getting, this approach still seems wrong to me. The user shouldn't be able to go back to the HomeFragment (and see the screen flicker when fragments are immediately switching back and forth) before she authenticates. I've also looked at this Android's official guide to implementing an authentication flow, but it too seems wrong to me, because a redundant third piece of UI is involved there (the MainFragment). I could replace it with a splash screen in my case, but it would still stay in the back stack and the user would be able to go back to splash screen, which is obviously nonsense.
So what would be the correct way to implement an authentication flow using the Android's new Navigation Component? The functionality I want is: if a user is not authenticated, then she's redirected to an authentication UI and if she presses the back button from there she should exit the application.
UPDATE: I know I could just listen to the back press event and close the application from there, but I still hope there's some elegant solution using Android's Navigation Component.
In your login fragment, you need to declare "Pop up-to" action from home fragment.
This pops all non-matching destinations from the back stack until
this destination is found.
"popUpToInclusive = true" pops the given destination from backstack
<fragment
android:id="#+id/loginFragment"
android:name="com.example.navigationsample.fragments.Login"
android:label="Login_Fragment"
tools:layout="#layout/layout_login">
<action
android:id="#+id/action_loginFragment_to_homeFragment"
app:destination="#id/homeFragment"
app:popUpTo="#id/loginFragment"
app:popUpToInclusive="true"/>
</fragment>
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.
I have a main activity where user provides an input according to which i jump to a activity deep inside the heirarchy eg:
Let activities be B->C->D->E
On user input it will jump from A to E.What i want to do is i want to add B C D onto the backstack so that when user press back button it navigate according to the heirarchy. Also i want to remove A from the backstack so after B app should exit. I know there are many related questions but I am not able to make out how exactly to do this. I have been following the tutorial for providing proper back navigation on android official site:Create Back Stack. In this tutorial i did not understand how PendingIntent is used or what upIntent is.I am new to android development so any help will be appreciated.ThankYou
Sounds like you need to use fragments within 1 activities framelayout. You can use FragmentManager to manage the backstack
more info:
http://developer.android.com/reference/android/app/FragmentManager.html