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.
Related
I have two fragments FRAGMENT A and FRAGMENT B. WhenI go from FRAGMENT A to FRAGMENT B I am adding FRAGMENT A in backstack using addtobackstack(null) and also using replace() method. The problem is when I call popbackstack() from FRAGMENT B --> FRAGMENT A then OnCreateView() and onViewCreated() calls again and It loads the recycler view again in FRAGMENT A. I know all the instance are not loaded again
but the problem is I do not want to load view again. Ex. in activity when i call finish previous activity remain same as we left.
NOTE : I don't want to use add() method in beginTransaction because it overlap other fragment.
Thanks
For reference:
One more importance difference between add and replace is: replace
removes the existing fragment and adds a new fragment. This means when
you press back button the fragment that got replaced will be created
with its onCreateView being invoked. Whereas add retains the existing
fragments and adds a new fragment that means existing fragment will be
active and they wont be in 'paused' state hence when a back button is
pressed onCreateView is not called for the existing fragment(the
fragment which was there before new fragment was added). In terms of
fragment's life cycle events onPause, onResume, onCreateView and other
life cycle events will be invoked in case of replace but they wont be
invoked in case of add.
In Short for your use case, you need to use add and if you don't want the fragment views to overlap then you might replace the Fragment B view background color with a solid color instead of transparent.
Also don't forget to add android:clickable="true" to the parent view of your second fragment so it catches the clicks and they don't get propagated to the fragment below. Something like this:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true">
f you are adding the Fragments to the android.support.v4.app.FragmentManager you also have to call popBackStack() on the same FragmentManager.
This code should solve the problem:
if (getSupportFragmentManager().getBackStackEntryCount() > 0){
boolean done = getSupportFragmentManager().popBackStackImmediate();
}
I am learning fragments but I am failing to understand the significance behind why fragments requires a Container.
The way I understand Fragments work is as follows :
FragmentActivity setContentview refers to a xml file which
defines where fragments would be located.
FragmentActivity creates instance of the fragments
Then assigns fragment to container.
FragmentManager then displays them.
The actual Fragment class then inflates a layout, and it is this layout which
contains all of the applications UI components.
(please correct me if I miss something here because I am only learning at the moment).
So why is the purpose of the Container why do we even need since in all the examples I have seen it is just a blank relative layout xml document.
Can different fragments share the same Container (since its just a RelativeLayout xml file)?
So in the example provided by google http://developer.android.com/training/basics/fragments/creating.html
They have a ListFragment and when item is selected through the use of the CallBack interface we eventually get back to this line of code :
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
My other question is:
1) Why does this line of code not replace the ListFragment (left side Fragment) with the article fragment. Since when it was initialised we see:
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
Instead ... the ListFragment remains on the left and the right Fragment is updated.
But the container fragment_container belongs to firstFragment this is the ListFragment.
And this is not the one that gets updated.
Do you see why I have the question ? This is not explained in the tutorial.
Here: http://marakana.com/s/post/1250/android_fragments_tutorial
And here: http://developer.android.com/guide/components/fragments.html
Read this and all will be clear:)
Fragment is a portion of Activity and can exist only inside an Activity. So you need a special type of activity that can handle fragment - it's FragmentActivity.
FragmentActivity without Fragments is almost like a normal Activity. But it has a FragmentManager to manage (add,remove,replace) fragments. When you want to add a Fragment to a FragmetnActivity you should specify where it should be placed (because fragment does not need to be fullscreen, just like GooglePlay-there are multiple small fragments). So this is why you need a container.
Can different fragments share the same Container (since its just a RelativeLayout xml file)?
Yes they can, you can replace one fragment with another within the same container.
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?
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.
I'm trying to add animation to my android app, and knew a lot about transition animation between activities, and about fragments. So I have MainActivity with some view (image), and SecondActivity which is empty itself, but contains fragments, which then needs to be used to display some detail information about this image. I've read about postponeentertransition() and it worked. But the problem is, that this fragment in second activity have links(or transitions) to the same kind of fragment.
Let's say in main activity I have set of images of cars, then I click one, second activity is starting and waiting for fragment loading, and then shows animation. And then, in this fragment I have "similar cars" recycler, and choose one of them, and wants, to show its details the same way, but with adding this fragment to the backstack (not replacing). So the problem is that transition name of the view in main activity and big image of fragment are the same (which is obvious), and transition name in fragment's recycler and big image of the next fragment have to be the same too(otherwise app doesn't know how to make the animation). On the other side, fragment (which was added) has to be the same class, but its different instance.
I just want to set up animation without crashing the existing architecture.:) If you have any solutions or advices how to make animation between different instances of one fragment, please help.)
Use setCustomAnimations on the Fragment transaction (see below). It doesn't matter if the instances are from the same class.
FragmentTransaction transaction = mActivity.getSupportFragmentManager().beginTransaction();
// To animate the fragment
// NOTE: Must be before replace/add otherwise it doesn't work
transaction
.setCustomAnimations(enter, exit, popEnter, popExit)
.replace(R.id.frame_container, fragment, null)
.commit();