'IllegalStateException: Activity has been destroyed' when 'getSupportFragmentManager()' called after Activity restart

Milo picture Milo · Feb 10, 2013 · Viewed 22.5k times · Source

I have a parent Fragment Activity that has a ViewPager which contains a child ViewPager. The child ViewPager contains Fragments for each page. I communicate between these child page fragments and the top parent Fragment Activity using a callback interface e.g.

public interface Callbacks {
    public void onItemSelected(Link link);
}

In the parent Fragment Activity I listen for onItemSelected events e.g.

@Override
public void onItemSelected(Link link) {
    Bundle argumentsFront = new Bundle();
    argumentsFront.putParcelable(FragmentComments.ARG_ITEM_ID, link);
    fragmentComments = new FragmentComments();
    fragmentComments.setArguments(argumentsFront);
    getSupportFragmentManager().beginTransaction().replace(R.id.post_container, fragmentComments).commitAllowingStateLoss();
}

Now this works fine when the app is first launched.

If you turn the device to change the orientation the Activity restarts. All fragments reinitialise themselves as I use setRetainInstance(true); (I do not call setRetainInstance(true) in the page Fragments of the child ViewPager as it is not supported). However if I click a list item in the Fragment of the child ViewPager I get this exception:

FATAL EXCEPTION: main
java.lang.IllegalStateException: Activity has been destroyed
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1342)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:578)

Does anyone know why this happens?

Thanks

Answer

Steven Byle picture Steven Byle · Feb 12, 2013

When you rotate the device, Android saves, destroys, and recreates your Activity and its ViewPager of Fragments. Since the ViewPager uses the FragmentManager of your Activity, it saves and reuses those Fragments for you (and does not create new ones), so they will hold the old references to your (now destroyed) original Activity, and you get that IllegalStateException.

In your child Fragments, try something like this:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    Log.v(TAG, "onAttach");

    // Check if parent activity implements our callback interface
    if (activity != null) {
        try {
            mParentCallback = (Callbacks) activity;
        }
        catch (ClassCastException e) {
        }
    }
}

Then when a selection occurs:

if(mParentCallback != null) {
    mParentCallback.onItemSelected(selectedLink);
}

Since onAttach gets called as part of the Fragment lifecycle, your Fragments will update their callback reference on rotation.