5

I'm getting really confused about this. I have an actionbar with list navigation. I click on the list to open 2 fragment one after another and display in the same activity. I'm basically replacing them using this method:

public void openFragment(AprilAppsFragment createdFragment){        
    if (createdFragment.getClass().isInstance(getDisplayedFragment()))
        return;

    FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction transaction = manager.beginTransaction();
    transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);

    transaction.replace( R.id.main_fragment, createdFragment, "displayed fragment"); 
    transaction.addToBackStack(null);
    transaction.commit();  
}

I open fragment A, then I open fragment B, then I rotate the screen. Fragment A is being recreated crashing my app

Whys is that, since I'm using replace? How do I avoid recreating fragments that no longer being shown, without losing possibility of back-pressing to them?

Vikalp Patel
  • 10,669
  • 6
  • 61
  • 96
Jacek Kwiecień
  • 12,397
  • 20
  • 85
  • 157
  • Can you add the stack trace from the crash? – ianhanniballake Feb 25 '13 at 19:19
  • it would be irrelevant. Crash occurs, when the fragment tries to fill it's content with data, but it fails to instantiate view components, since it's not even shown – Jacek Kwiecień Feb 25 '13 at 19:20
  • Do you call that method from the `OnNavigationListener`? If yes keep in mind that the listener will be triggered by the activity creation/recreation. – user Mar 01 '13 at 14:05
  • 1
    The statement `if (createdFragment.getClass().isInstance(getDisplayedFragment())) return;` is very fishy. Can you please show us the stack trace? Stack traces are never irrelevant. – Sherif elKhatib Mar 04 '13 at 09:54

5 Answers5

10

Your problem is that you are not saving state for your fragments, and since you haven't added

android:configChanges="orientation|screenSize"

your first fragment is called again, and since you have no saved state your app crashes. So its good that you add the line above in you Activity declaration in the manifest like:

<activity android:name=".yourActivity" android:configChanges="orientation|screenSize"

and Override the onSaveInstanceState and save states for both your fragments. And in your onCreate just do this check:

if(savedInstanceState != null){
fragmentA = (FragmentA) fragmentManager.getFragment(savedInstanceState, stringValueA);
fragmentB = (FragmentB) fragmentManager.getFragment(savedInstanceState, stringValueB);
}

And then check if any of your fragment is not null than create its instance and set that to fragmentTransaction.relplace. Or do this in your for openFragment method.

Cheers,

AliR
  • 2,065
  • 1
  • 27
  • 37
  • 1
    It doesn't really answer why activity on recreation recreates all the fragments, even those which were replaced. configChanges actually stops activity from recreation but it's not working with ActionBarSherlock and my be worth a try only on post ICS systems – Jacek Kwiecień Mar 10 '13 at 09:41
  • Read the answer in this thread: http://stackoverflow.com/questions/14184182/why-wont-fragment-retain-state-when-screen-is-rotated – AliR Mar 11 '13 at 00:12
  • Not too often such an irritating issue is fixed with one line of code, but there ya go. Thanks, @AliR. – mwieczorek Jun 13 '16 at 06:19
2

Fragments save their state (and the location on the back stack) automatically on rotation. Make sure you aren't recreating your fragments or calling openFragment in your onActivityCreated or onCreate methods.

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
2

Your problem is that your activity is getting recreated, which is causing you to re-setup your list navigation, which is causing the default (first) position to be triggered. You need to save the selected index between activity destruction and activity recreation. Here's an example:

@Override
public void onCreate(Bundle savedInstanceState) {

    // onCreate implementation...

    // Must come after setListNavigationCallbacks is called
    if (savedInstanceState != null) {
        int index = savedInstanceState.getInt("index");
        getActionBar().setSelectedNavigationItem(index);
    }
}

@Override
protected void onSaveInstanceState(Bundle outState) {

    super.onSaveInstanceState(outState);
    outState.putInt("index", getActionBar().getSelectedNavigationIndex());
}
Jason Robinson
  • 31,005
  • 19
  • 77
  • 131
1

i had a similar problem and what i do is to add a code line in my Androidmanifest.xml (inside your activity that u want to stop recreated):

android:configChanges="orientation"

And one more thing, i learned that fragment is a kind of sub activity and doesn't an activity, We must to extends an activity fragment for getting a support with fragments, and the activity that extands the activity fragment is the actually activity that holds a "sub's activities" that called fragments.

I hope i help u...

Liran Peretz
  • 580
  • 8
  • 11
1

Add this to your activity definition in your AndroidManifest.xml file:

android:configChanges="keyboardHidden|screenLayout|orientation|screenSize"

That will keep the activity from restarting and the FragmentManager from automatically recreating the fragments that it has.

If you need the activity to restart on rotate, then you'll have to look for savedInstanceState being passed into onCreate and then query the FragmentManager for your fragments using the tags you supplied.

Jess Anders
  • 968
  • 1
  • 8
  • 11