Replacing a Fragment with itself does not show anything
Asked Answered
S

4

7

I'm trying to decide and show a fragment in activity's onResume method, but in case a previously added fragment is chosen again, then the activity goes blank.

Sample code (with one fragment):

@Override
protected void onResume(){
    FragmentTransaction trans = getSupportFragmentManager().beginTransaction();

    trans.replace(R.id.myLayout, fragA);

    trans.commit();
    getSupportFragmentManager().executePendingTransactions();
}

With above code, when the activity is created for the first time, it shows fragA correctly, but in case I press Home Key and then switch back to my activity (in order to provoke onResume again), it all goes blank (seems like fragA is removed).

Is replacing a previously added fragment removes itself? or how not to loose a fragment if it is replaced by itself?

Sprightly answered 19/2, 2013 at 13:53 Comment(0)
S
6

You can't replace a fragment with itself. The first half of a replace is a removal of the previous fragment at that id. Once a fragment is removed it can no longer be added or used by the fragment manager (so the add portion of the replace will not work properly).

Depending on your use case, you have two options:

  1. Create a new fragment instead of reusing the existing instance
  2. Use some other method to see if its necessary to replace your fragment

Finally, you probably don't need to call executePendingTransactions.

Salami answered 19/2, 2013 at 14:2 Comment(10)
I initialize fragA in onCreate, which means i do keep reference to my fragment. So why doesn't it allow to add it after removing that fragment?Sprightly
Because of exactly what I said. Once you remove an instance of a fragment, you can NOT add it any longer. Its destroyed, finished, no longer usable.Salami
One other thing to check is that R.id.myLayout is the id of the container you are wishing to put your fragment into. If it is, try switching your replace call to be replace(R.id.myLayout, new FragmentAClass())Salami
@Waqas Although this answer is marked as accepted, it did not work for me, when I created a new instance of the fragment (suggestion #1) nothing happened, the current fragment was not replaced.Clanton
I doubt about this "Once a fragment is removed it can no longer be added or used by the fragment manager", I've tried with two fragments and replace one by another again and again, it works well.Analyse
@JustinBreitfeller this answer is simply wrong. No argument about it.Schulz
I could change my answer to be "it should no longer be added...". But just because it may be possible to re-use a fragment after destruction doesn't mean its a good idea. There are state issues, memory leak issues, and etc that would all have to be thoroughly addressed.Salami
@JustinBreitfeller ~"You can't replace a fragment with itself." Then how do you refresh the fragment's layout?Coquette
Surely popping the back stack reuses the old fragment that was there?Speculation
Placing a fragment on the backstack does not call onDestroy of the fragment like replace does.Salami
C
4

You can try:

if( !(getSupportFragmentManager().findFragmentById(R.id.myLayout) instanceof FragmentA) ) {
    FragmentTransaction trans = getSupportFragmentManager().beginTransaction();

    trans.replace(R.id.myLayout, fragA);

    trans.commit();
}

And I assume that fragA is FragmentA class object.

Corene answered 19/2, 2013 at 14:21 Comment(3)
R.id.myLayout points to the layout in which fragA is injected. I dont think findFragmentById(R.id.myLayout) will return me reference to my fragment.Sprightly
If your fragment is in this container then it will return a reference to this injected fragment. Then you can check if it is instance of your fragment's class.Variant
this works, and it's pretty interesting solution if you are creating fragments inside fragments.Kalagher
S
3

Finally, I had to put a check before replacing fragments. In case, an (already added) fragment is requested for replace again, I had to check if its already added then ignore the replacement, else proceed. For example:

@Override
protected void onResume() {
    if (!fragA.isAdded()) {
        FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
        trans.replace(R.id.myLayout, fragA);
        trans.commit();
        //getSupportFragmentManager().executePendingTransactions();   //unnecessary
    }
}
Sprightly answered 20/2, 2013 at 13:3 Comment(0)
H
0

When referencing back to a created Fragment please do make sure to try adding the

fragmentTransaction.addToBackStack(null); 

method right before committing so that your Fragment is resumed instead of destroyed as mentioned in the developer guides.

If you don't call addToBackStack() when you perform a transaction that removes a fragment, then that fragment is destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you do call addToBackStack() when removing a fragment, then the fragment is stopped and is later resumed if the user navigates back.

You can find this at the end of this page.

Hide answered 17/10, 2018 at 12:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.