I have the following code that adds fragments to the same container R.id.container. First I add one fragment, then after user interacts with it, I add another one with the same code
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
My question when I cell getSupportFragmentManager().getFragments() I can see two fragments. Why doesn't replace actually replace but add?
It keeps the two fragments because
addToBackStack(null);
means the user is able to revert back to the previous state.
If you add fragment1 (using replace), then fragment2, only fragment2 is shown, but if the user press back, the FragmentManager needs to show fragment1, so it keeps a reference to both fragment.
Related
I have a problem when I click back button while using ViewPage. When I enter to ViewPage after going out and coming back, it shows me the content of previous ViewPage, not new ones.
I'm entering to ViewPage from a RecyclerView and I want to change ViewPage content by clicking on items of RecyclerView.
So my problem is that why ViewPage is not reset to new content?
before committing the fragment do this! it won't remember the last open fragment and please read about BackStack management in fragments here
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
If by saying ViewPage you mean 'ViewPager'. Then you must be displaying the content using a fragment. So when you open the ViewPager screen 'Replace' the fragment with new content.
Use this syntax:
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, new Frag_four()).commit();
Or this one
getFragmentManager().beginTransaction()
.replace(R.id.container, new Frag_four()).commit();
You are facing this issue because may be you are not removing previous content from the container. So just give it a try.
EDIT:
In your fragment displaying activity place the following code in 'OnDestory' method.
getFragmentManager().beginTransaction().remove(getFragmentManager().findFragmentById(R.id.your_container)).commit();
This will empty the container. So next time it will load the new fragment.
I have 3 fragments added to stage in one and the same container. Two fragments are added with addToBackStack method:
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
And final one is added without back stack:
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.container, fragment);
fragmentTransaction.commit();
All three co-exist fine because as I understand if a fragment is added using a backstack, then it's not destroyed when another fragment is added.
The last one is added without a backstack, meaning that once I call replace it should be destroyed.
However, this does not happen and when I call
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.container, myNewFragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
I can still see that there are 4 fragments total in my R.id.container, which is not that I expect.
How can I make my 3rd fragment disappear when I call replace method when adding 4th fragment?
By calling addToBackStack(), the replace transaction is saved to the
back stack so the user can reverse the transaction and bring back the
previous fragment by pressing the Back button.
So in your case you are replacing the third fragment with the fourth fragment . It means for reversing the transaction they need fragment3 also . So they will not destroy it.
Working with fragments I've always used replace() for my transactions, but I wish I didn't have to save instance states anymore to restore a fragment's view and prevent reloading when coming back to that fragment. So, I've decided to work with add(). The thing is when I add another fragment, the previous fragment view remains in the background and that's fine (that's the behavior I expected), but the problem is I can actually interact with the views in the background. Example:
Fragment A has a Button
Fragment B has a TextView
When I add Fragment A and later add Fragment B, I'm able to click on Fragment A's Button, even staying on Fragment B's view.
I'm using:
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction().
add(getRootViewContainer(),fragment,fragment.getClass().getSimpleName());
if (shouldGoBack)
fragmentTransaction.addToBackStack(fragment.getClass().getSimpleName());
where getRootViewContainer() returns the id of the FrameLayout I'm using as my activity main container.
Now, is it really the default behavior of add()?
If so, is there a proper way to avoid this or one just has to use replace()?
What you can do here is just hide previous fragment at the time of transaction of current fragment.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment newFragment= new MyFragment ();
ft.hide(CurrentFragment.this);
ft.show(newFragment);
ft.commit();
It worked for me just try it.
FragmentTransaction.hide(fragmentBehind); //works for me!
example :
//I have it globally available
FragmentTransaction trans = MainActivity.getManager().beginTransaction();
//not globally
FragmentTransaction trans = getFragmentManager().beginTransaction();
MapFragment newFragment = new newFragment();
trans.add(R.id.fragmentContainer, newFragment, tag);
trans.hide(this);
trans.addToBackStack(tag);
trans.commit();
Yes, this is a default behaviour of add().
If you really don't want to user replace(), you can try to disable views which are inside "old" fragment.
I have an activity with a FrameLayout in it.
The activity should show four steps, and each step is a Fragment. When I want to go back-further, I don't want my fragments to be recreated. I would like to retain them and simply replace their view in my fragment.
I used to first create my Fragments and add them in the backstack like this:
Fragment step= new Frag1ActCompleteFragsCommTrack();
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.add(step, ""+onStepNr);
ft.addToBackStack(null);
ft.commit();
notice that I don't show it, I simply create it and add to the backstack.
So, once I need one of my fragments to show, I add it (in this example I don't remove any fragment from the framelayout just because it's my first add):
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.add(R.id.my_frameLayout, step);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
So: the problem is that I obtain a
Caused by: java.lang.IllegalStateException: Fragment already added: Frag1ActCompleteFragsCommTrack{410dcb20 #0 id=0x7f050041 -1}
But I think I can't add directly into my framelayout the first time, otherwise the next time I replace it, I could lose my fragment. Am I right? So.. what's the best practice for retaining fragments that could interchange each other in a framelayout?
Ladies and gentlemen, I did it!
If you add a Fragment, and you want it to be shown in a framelayout, remember to put it in the Fragment backstack. That's it! If you replace it in the framelayout with another one, no worries: you can put it back by finding it thanks to its tag.
It was easier than I thought actually
//step is an int describing the step associated to the fragment I wanna place
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.replace(R.id.act_complete_track_frameLayout, f, ""+step);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
if(firstAttach)
ft.addToBackStack(null);
ft.commit();
imagine a fragment with tag "1" replaced through the code above by a fragment with tag "2". If I want to go back to step1, I reuse that code by obtaining my old fragment with getSupportFragmentManager().findFragmentByTag("1")
To be short, I thought that FragmentTransaction.replace removed the fragment from the backstack as well. That seems not to be the case (luckily)
You can always do something like fragmentManager.putFragment(yourFragment);
If I understand correctly, you are trying to add all the fragments but not show them until you are ready. FragmentTransaction.add() doesn't exactly do that though. It will also be shown after its added. You should use hide() after adding each fragment, and then later you can use show() to make it visible, and hide() again to make other fragments invisible.
Like this:
Fragment step = new Frag1ActCompleteFragsCommTrack();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(step, ""+onStepNr);
ft.hide(step);
ft.commit();
Then later:
Fragment step = getSupportFragmentManager().findFragmentByTag(""+onStepNr);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.show(step);
// may want to hide other fragments here
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
I'm currently using a ViewGroup (SwipeyTab implementation) to switch between Fragments. However, some Fragment "pages" get replaced by other Fragments on the same Tab, so I initially tried:
FragmentTransaction ft = fragment.getFragmentManager().beginTransaction();
ft.remove(currentFragment);
ft.add(newFragment,"");
ft.commit();
That code would remove the current fragment but not add newFragment (from Logcat, it would get instantiated but not appear).
I ended up adding it in the FragmentPagerAdapter.getItem(int position) call based on current state (based on this: Replace Fragment inside a ViewPager). However, I'd like to be able to add each newly replaced fragment to be part of the back stack.
I tried adding to backstack before removing the fragment:
currentFragment.getFragmentManager().beginTransaction().addToBackStack(null).commit();
FragmentTransaction ft = fragment.getFragmentManager().beginTransaction();
ft.remove(currentFragment);
ft.commit();
and that didn't work - it added the last fragment to the backstack, so when I pressed back, it would just reload the current fragment.
Is there anyway I can add a fragment to the backstack that has been replaced in the "non traditional" way?