java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

在使用Fragment的过程中,常常会遇到在Activity的onSaveInstanceState方法调用之后,操作commit或者popBackStack而导致的crash.

因为在onSaveInstanceState方法之后的操作状态可能会丢失,因此Android framework默认会抛出一个异常.

对于commit方法来说,单纯避免这个异常很简单,使用commitAllowingStateLoss方法即可.但是popBackStack以及 popBackStackImmediate也都会检查state(checkStateLoss),特别需要注意的是Activity的 onBackPressed方法

如果onBackPressed在onSavedInstanceState之后调用,那么就会crash.

onBackPressed的调用时机:

* targetSdkVersion <= 5,在onKeyDown中调用

* targetSdkVersion > 5,在onKeyUp中调用

onSavedInstanceState的调用时机(如果调用的话):

* 一定在onStop之前

* 可能在onPause之前,也可能在onPause与onStop之间

需要注意的是: onSavedInstanceState方法不一定会调用,只有在Activity因为某些原因而被Framework销毁,并且之后还需要重新创建的情况,才需要调用(例如:旋屏,或者内存不足而回收返回栈中的某些Activity)

举例:

* Activity A在前台时,屏幕逐渐变暗直至锁屏,那么A的onSavedInstanceState会被调用

* Activity A start Activity B,Activity A的onSavedInstanceState会被调用

* Activity A因为返回键或者finish调用而返回到上一个界面,那么A的onSavedInstanceState不会被调用

因此,当onBackPressed在onSavedInstanceState方法之后调用,就一定会crash.解决方法主要有两种:

重写Activity的onSavedInstanceState()方法,并且注释掉super调用.

这种方法能避免crash,但是它会导致整个Activity的状态丢失.以DialogFragment为例,正常情况下,显示的 DialogFragment在旋屏Activity重新创建之后,不需要我们处理,Dialog会自动显示出来(参见 DialogFragment.onStart()),但是注释掉Activity的onSavedInstanceState()方法之 后,Fragment状态丢失,Activity重新创建之后,Dialog也就不会再显示出来了.

更好且通用的做法:在调用commit,popBackStack以及onBackPressed方法之前,判断 onSavedInstanceState()方法是否已经执行,并且onResume方法还没有执行,如果不是,那么直接操作,否则加入到 pending队列,等待onResumeFragments或者onPostResume之后再执行.

注意:不要在onResume中操作,因为这时候FragmentManager中的mStateSaved依然可能是true.(如果执行顺序是 onSavedInstanceState()->onPause()->onResume() 或者 onPause()->onSavedInstanceState()->onResume());

public void endPaintingPager(int index) {
        if (mFirstLevel == PAINTING_PAGER) {
            mFirstLevel = PAINTER_START;
            if (!mIsStateSaved) {
                getSupportFragmentManager().popBackStack();
            } else {
                mPopBackStackRunnable = new Runnable() {
                    @Override
                    public void run() {
                        getSupportFragmentManager().popBackStack();
                    }
                };
            }
        }
    }
@Override
    protected void onPostResume() {
        super.onPostResume();
        if (mPopBackStackRunnable != null) {
            mPopBackStackRunnable.run();
        }
    }