I'm building an application that uses nested fragments. The first layer of fragments is an animated menu where one fragment is the menu and the other is the content. Some of the content fragments will also contain fragments (child fragments). I want to disable the back button from popping the fragment stack on the first layer of fragments however.
I have successfully delegated the back button to work with the child fragments. For the top level fragments I want to reuse them if they have been created so I save the fragments to a hash and when a new fragment is added I just remove() the current fragment then do a replace() with the new fragment so the view is updated. I never call addToBackStack. However when trying to navigate back to a previously created fragment (that is saved in the hash) I get the error:
java.lang.IllegalStateException: No activity
But only when getChildFragmentManager() is called from re-added nested fragments. I cannot for the life of me figure out why. Any suggestion?
Related
I've created an app, that has a main activity with a drawer menu so the user can click on some option and a fragment is open inside the activity.
What I'd like to do is to have several screens in one of the options and to navigate between them by tabs/slide the screen.
I saw an example of doing it inside one activity and with a fragment per 'sub-screen', my question is: how can I do it when I'm already 'inside' a fragment?
Thanks
Fragments can support having other Fragments inside them. The key to making this work is to remember to use getChildFragmentManager() to get the Fragment's FragmentManager instead of getFragmentManager() which gets the Activity's FragmentManager.
If you want to swipe between views, use a ViewPager inside your Fragment UI. The ViewPager will use a FragmentPagerAdapter to handle the Fragments for display.
In my application I am making use of navigation drawer which is in the MainActivity and this navigation drawer has say 5 fragments. I am not maintaining any backstack of these fragments.
Now, the first fragment has one button which when clicked pushes a fragment (which I call an inner fragment). Here, I am maintaining a backstack because I want to get back to the first fragment from the inner fragment.
Now, I have a requirement in which I want to navigate from an activityA to the inner fragment.
Is this possible?
One way that I have thought of is to have the push code inside the first fragments create method (and make this conditional).
But I don't think its an appropriate way. Any suggestions would be helpful.
What I already known is:
after fragmentTransaction.replace(), current fragment's onStop() function will be called
while fragmentTransaction.add() won't.
and after calling fragMgr.popBackStack();, we will return to previous fragment no matter fragmentTransaction.replace or fragmentTransaction.add() is used
So what does fragmentTransaction.replace do?
I can understand we can "add" a fragment opon a previous fragment and later return to previous fragment by popBackStack(), BUT:
if previous fragment is "replaced" by current fragment, I guess previous fragment is removed and current fragment is added in, how can it return to previous fragment when popBackStack() called?
You can add multiple fragments to a container and they will be layered one on top of the other. If your fragments have transparent backgrounds you will see this effect and will be able to interact with the multiple fragments at the same time.
This is what will happen if you use FragmentTransaction.add on a container. Your added fragment will be placed on top of your existing fragment.
If you use FragmentTransaction.replace(R.id.container,fragment) it will remove any fragments that are already in the container and add your new one to the same container.
You can also use the add method without a container id and your fragment will simply be added to the list of fragments in the FragmentManager and you can recall these at any time by their Tag value.
You can still return to a previous configuration IF you added the transaction to back stack. You can do this even if a previous operation removed a fragment. The removed fragment is remembered in the transaction and popping the back stack brings it back.
Two choices
Let's say you have a fragment container.
And, your task is to add a fragment into the container.
You can do this by calling any of the following methods
1) add(containerId,fragment)
2) replace(containerId,fragment)
But both methods differ in behavior !!!
Although both methods will add your fragment into the fragment container, their innards(internal working) differ based on the two possible states of the fragment container.
When fragment container
1) does not have any fragment in it.
2) already have one or multiple fragments attached to it.
Let's see what happens when we call add() and replace() method.
Case 1: When there is no fragment attached in a container
In this case, both methods will add the fragment to the container. So they will produce same effect.
Case 2: When the fragmentContainer already has fragment/fragments
add(): adds the new fragment on the top another fragment
replace(): removes everything then adds the new fragment
Example
So suppose the Fragment container has fragments[A->B->C].
Now you want to add a new fragment D.
add() method result will be [A->B->C->D]
replace() method result will be [D]
Relevant Link:
Check this Demo project for better understanding.
I have a ZooFragment which contains a ViewPager.
This ViewPager has three children: LionFragment, LeopardFragment, and TigerFragment, each of these children can request transaction to call a new ZooFragment.
When a ZooFragment called zooA (with arguments) is initialized, all three children in ViewPager display content. From any child fragment, user touch will call a new ZooFragment called zooB (with different arguments, of course).
Based on transaction action from child fragment to ZooFragment:
1.If I use transaction.replace(), zooB will be blank, all three children in zooB display no content, empty. At zooB, pressing hardkey Back from navigation, zooA becomes empty.
2.If I use transaction.add(), zooB won't be blank, following by a Back button press, zooA gets empty.
In ZooFragment class, I do loading data in onCreateView(), so what is the reason why all the child fragments in ViewPager get empty?
Please do not replace the fragments in the ViewPager, just show (using transaction) in any other contained in the same layout as that of ViewPager and that container should be a FrameLayout. Also device a mechanism to know when and what fragment comes into view. Then request for a fresh data from a utility that responds to update your fragment. I do not think onDestroyed will be called in case of all the fragments in the ViewPager.
Fragments in the ViewPager are fixed, so should there contents will not go till the application manager wants to destroy it.Instead of trying to replace the fragments in the adapter, try to give a different set of fragments and notifyDataSet changed, or take the advantage of FrameLayout to show another fragment over the view pager tab's current fragment.
There is my solution that works:
Swipe Gesture applied at Fragment level along with ViewPager with it's default swipe disabled
I have a custom widget that performs FragmentTransaction.replace when buttons are pressed. Currently, my code is set up such that the first time a fragment is created, it attaches a bunch of stuff to the view that isn't originally part of the xml layout file.
When the app first launches, all my fragments show stuff correctly, however, let's say I start on Fragment A. I can then transition to Fragment B (with B showing up correctly), however, when I transition back to Fragment A, all the stuff I have attached to the view of Fragment A is now gone. I know this happens because onCreateView is called which probably means the Fragment's view is re-generated when FragmentTransaction.replace is called.
Is there a way where I can keep my fragments around instead of having them re-generate their views when FragmentTransaction.replace is called?
Thanks!
Instead of using fragmentTransaction.replace, use fragmentTransaction.show and fragmentTransaction.hide.
That will keep your fragments from being destroyed.