java.lang.IllegalStateException: Failure saving state: active has cleared index in fragment

R4j picture R4j · Sep 30, 2013 · Viewed 9.5k times · Source

First, my app has structure like this:

 SpashActivity -> MainActivity -> switching between many fragments

My app use SlideMenu to switch between fragments. I have to use attach instead of replace to keep fragment state. It's look like:

  public void switchContent(int index, String fragmentTag) {                
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction transaction = fragmentManager.beginTransaction();
    if (fragmentManager.findFragmentByTag(fragmentTag) != mContent) {
        if (!mContent.isDetached()) {
            transaction.detach(mContent);
        }
        if (null == fragmentManager.findFragmentByTag(fragmentTag)) {
            switch (index) {
            case 0:
                mContent = new CategoryFragment();
                break;
            case 1:
                mContent = new BookFragment();
                break;
            case 2:
                mContent = new BookDetailFragment();
                break;
             // etc
            }
        } else {
                mContent = fragmentManager.findFragmentByTag(fragmentTag);              
        }

        if (mContent.isDetached()) {
            transaction.attach(mContent);
        } else if (!mContent.isAdded()) {
            transaction.add(R.id.content_frame, mContent, fragmentTag);
        }

        transaction.addToBackStack(null);
        transaction.commit();
        fragmentManager.executePendingTransactions();
    }
    Handler h = new Handler();
    h.postDelayed(new Runnable() {
        public void run() {
            getSlidingMenu().showContent();
        }
    }, 50);
} 

When the back stack count down to zero, my app has to exit:

 @Override
public void onBackPressed() {
    if (0 == getSupportFragmentManager().getBackStackEntryCount()) {
        // show confirm exit dialog.
        // If user press ok, try to exit, the splash activity will call finish()  
         // if(dialog == ok){ 
           Intent intent = new Intent(MainActivity.this, SplashActivity.class);
           intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
           intent.putExtra(SplashActivity.EXIT_KEY, true);
           startActivity(intent);
         // }  
    } else {
        super.onBackPressed();
    }
}

But sometimes (not always) I got the exception and crash my app when user press back many times (even the confirm exit dialog not appear - mean back stack count greater than zero):

  09-30 20:32:53.419: E/AndroidRuntime(796): Uncaught handler: thread main exiting due to uncaught exception
  09-30 20:32:53.470: E/AndroidRuntime(796): java.lang.RuntimeException: Unable to pause activity {com.org.scgroup/com.org.scgroup.MainActivity}: java.lang.IllegalStateException: Failure saving state: active BookDetailFragment{43e7e0d8} has cleared index: -1
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3162)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3119)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:3102)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.app.ActivityThread.access$2400(ActivityThread.java:119)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1870)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.os.Handler.dispatchMessage(Handler.java:99)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.os.Looper.loop(Looper.java:123)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.app.ActivityThread.main(ActivityThread.java:4363)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at java.lang.reflect.Method.invokeNative(Native Method)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at java.lang.reflect.Method.invoke(Method.java:521)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at dalvik.system.NativeStart.main(Native Method)
  09-30 20:32:53.470: E/AndroidRuntime(796): Caused by: java.lang.IllegalStateException: Failure saving state: active BookDetailFragment{43e7e0d8} has cleared index: -1
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.support.v4.app.FragmentManagerImpl.saveAllState(FragmentManager.java:1716)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.support.v4.app.FragmentActivity.onSaveInstanceState(FragmentActivity.java:532)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at com.actionbarsherlock.app.SherlockFragmentActivity.onSaveInstanceState(SherlockFragmentActivity.java:126)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at com.jeremyfeinstein.slidingmenu.lib.app.SlidingFragmentActivity.onSaveInstanceState(SlidingFragmentActivity.java:51)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at com.org.scgroup.MainActivity.onSaveInstanceState(MainActivity.java:324)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.app.Activity.performSaveInstanceState(Activity.java:1022)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1180)
  09-30 20:32:53.470: E/AndroidRuntime(796):    at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3144)
  09-30 20:32:53.470: E/AndroidRuntime(796):    ... 12 more

The onSaveInstanceState method:

  @Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    try {
        Ln.d("onSaveInstanceState");
        outState.putInt(CURRENT_FRAGMENT_KEY, currentFragment);

        if (0 < getSupportFragmentManager().getBackStackEntryCount()) {
            getSupportFragmentManager().putFragment(outState, "mContent", mContent);
        }
    } catch (Exception ex) {
        Ln.e(ex);
    }
}

Could you please tell me where I am wrong? Thanks in advance.

Answer

artkoenig picture artkoenig · May 28, 2016

The state of your fragments is automatically saved and restored, there is no need to do anything in your onSaveInstanceState method. Don't hold any references to your Fragments in your Activity (in your case currentFragment, mContent), if you need a certain Fragment, get it from FragmentManager by e.g. findFragmentByTag.