Does Navigation Components popBackStack() retains Fragment state? - android

When I navigate from one Fragment to another with the new Navigation Components, I can do it successfully with the following:
btn_walk.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_action))
Now, if I pop the backstack from the destination Fragment with
findNavController().popBackStack()
The Fragment that launched that Fragments recreates itself again, but the state is not being saved, I have been looking around to see how to fix it, but I don't really know if actually how to do an .add function with the navigate() from Navigation components
This gif shows the navigation from one fragment to another, when popping the stack from the destination fragment, it recreates the fragment that launched that one instead of saving the state of it.
Using the fragmenttransaction.add() method does maintain the instance of that fragment alive also if I pop the back stack.
Is there any way to do the same with Navigation Components ?
I have also readed this Navigation Architecture Fragment Reload Problem but it's unclear how it should be solved.

Fragments automatically restore their saved state when they return from the back stack: that is true with our without Navigation. Seems like the problem is with how you've coded your Fragment.
You can confirm this is a problem with your Fragment by turning on 'Don't keep activities', hitting the home button, then returning to your app and see if the Fragment restores its state perfectly. You can also test the case where you handle configuration changes (i.e., rotating the device) correctly - again, you should be able to restore your state exactly where you were. If you handle both those cases, then it'll work great in Navigation as well.

Related

Navigation resets when switching fragments

I have the following navigation xml on a BottomNavigationView, however when the user navigates inside the 1st fragment and then navigates to another fragment using the BottomNavigationView and then comes back to the initial fragment, it resets all the way to the default 1st fragment the navigation to a deeper fragment does not persist, i assume this is because the fragment gets recreated and from what i've looked at on other questions is that there is a way to save the data to re-set any text values on text fields or similar stuff, however i haven't seen if theres a way to avoid the fragment from being destroyed and re-created in order to make the navigation and whatever changes the user had previously made to the view persist.
Is there a way to do that, or should i use a savedInstance in such a way that it re-navigates to the previously navigated fragment?
Part of Navigation 2.4.0 is support for multiple back stacks - i.e., the ability for each tab of a bottom navigation bar to save its state, restoring that state when you reselect that tab.
As per that blog post:
If you’re using NavigationUI, our set of opinionated helpers for connecting your NavController to Material view components, you’ll find that multiple back stacks is enabled by default for menu items, BottomNavigationView (and now NavigationRailView!), and NavigationView. This means that the common combination of using navigation-fragment and navigation-ui will just work.
This means that if you are using the setupWithNavController methods, then upgrading to Navigation 2.4 will give you support for multiple back stacks immediately. You can verify that by going to your order fragment (thus building a back stack on that first tab), going to a different tab, then tap on the first tab again to reselect it.
Of course, it is your fragments state, not the instances themselves that are saved and restored. This means that each individual fragment must still save its state properly.

Go to a specific fragment from anywhere keeping backstack

I'm updating the old navigation system from my app to jetpack navigation and I'm facing an issue:
From a DialogFragment which can be displayed from almost any fragment in the app, I have a button which leads to a specific Fragment. I've found in the documentation global actions, but it seems they clear the entire navigation backstack when you navigate with one of these and I need to keep my backstack, just add this new fragment to it from anywhere. What's the solution to this problem ?
Thanks

DialogFragment closes when navigating from it to another fragment

Currently in my navgraph i have dialog fragment destination ( Fragment(dialog) type). When i'm navigating to this dialog and then try to navigate to another fragment from this dialog destination, dialog is closing which in my opinion is upredictable behaviour.
Now i'm only navigating to the next fragment like this.
findNavController().popBackStack(R.id.testFragment, true)
I want to dialog not closing and only navigate to another dialog like a default fragment. How can i achieve this ?
As per this issue, this is working as intended:
There's a couple of problems here relating to how Dialogs and Fragments work:
Dialogs are separate windows that always sit above your activity's window. This means that the dialog will continue to intercept the system back button no matter what state the underlying FragmentManager is in or what FragmentTransactions you do.
Operations on the fragment container (i.e., your normal <fragment> destinations) don't affect dialog fragments. Same if you do FragmentTransactions on a nested FragmentManager.
The initial release of Navigation's <dialog> support did not take these limitations into account and would treat dialog destinations just like any other in that, from Navigation's point of view, they could be put on the back stack and treated like any other <fragment> destination.
As that's not actually the case, we've made a few changes for Navigation 2.1.0-alpha06 to ensure that Navigation's state of the world matches what you actually see on the screen and prevent crashes like that in comment#5.
The summary of this is that <dialog> destinations are now automatically popped when navigate to a non-dialog and non-activity destination, such as a destination. For reference, this was done in https://android-review.googlesource.com/996359 and https://android-review.googlesource.com/1007662
So it is expected when you navigate to a non-dialog destination that any dialog destination is popped off the back stack.

BottomNavigation Fragment state

I have a BottomNavigation implemented in my app. when i tap on navigation items it shows their respective fragments, it is working fine. I have implemented a progress bar in every fragment so whenever i select a fragment from BottomNavigation the progress bar displays, my question is when i select any option from BottomNavigation progress bar shows then fragments load but when the fragment is loaded it should gets saved when i come back to that option from BottomNavigation it loads again... is there any way to save the state of that fragment so that it only loads for the first time.
Use onSavedInstanceState(Bundle) This will get you the required behavior, so this method is called before an activity may be killed so that when it comes back some time in the future it can restore its state.
Here i use activity which in respect is any activity, even if its a fragment, this example is from the official documentation.
For example, if activity B is launched in front of activity A, and at some point activity A is killed to reclaim resources, activity A will have a chance to save the current state of its user interface via this method so that when the user returns to activity A, the state of the user interface can be restored via onCreate(Bundle) or onRestoreInstanceState(Bundle).
check out this cool link, it describes everything and a little bit more: https://inthecheesefactory.com/blog/fragment-state-saving-best-practices/en

How to know if all fragments were detached?

On my app I am using a Main Activity, which has a Navigation Drawer, and as the user go to an options from the drawer, it will change the fragment beging displayed accordingly to the option selected.
If the user hit's "Back button" several times, it will go back to a point in which it will reach my Main Activity, which is a blank and empty layout.
When I reach this point (my main activit, empty), I would like to exit the app, or, open the Navigation Drawer.
The problem is, I don't know any event that shows me that I am back to the Main Activity. I checked the onResume, but it's never called, which makes sense, since the main activity has never been stopped.
I thought perhaps there would be an event from the fragment manager that would be called on the Main Activity when a fragment was detached, and from there I could check if there was no fragment at all attached?
When you push your first fragment, add a tag to it. Something like
transaction.replace( R.id.rootContainer, firstFragment, "rootFragment");
Whenever user presses back button, you can get your rootFragment from FragmentManager
FirstFragment myFragment = (FirstFragment) getSupportFragmentManager().findFragmentByTag("rootFragment");
And check if this fragment is visible or not, by myFragment.isVisible(), if not, then keep popping the stack, if it is visible, it means user is on the first fragment. Now you can either quit the app, or show your menu drawer.
Good night good sir. Thank you for your tip.
I used a different approach, based on your repply, that gave me quite a few insights.
On main activity, I Overrided the onKeyDown and check if it was pressed the Back Button. If yes, then I check the size of my Back Stack.
Uppon that, I decide if I want to finish my application.
Also, thanks for the tip of "labeling" the fragments on the back stack, didn't know I could do that.

Categories

Resources