Can not perform this action afte
1.onSaveInstanceState()方法的调用时机
在 Activity 被销毁之前被调用来保存每个实例的状态,这样就可以保证该状态能够从 onCreate(Bundle) 或者onRestoreInstanceState(Bundle)恢复过来。
本方法在 Activity 可能被销毁前调用,这样当该 Activity 在将来某个时刻重新回来时可以恢复其之前的状态。例如,如果 Activity B 启用后位于 Activity A 的前端,在某个时刻 Activity A 因为系统回收资源的原因要被销毁,Activity A 有机会通过 onSaveInstanceState() 来保存其用户界面状态,使得将来用户返回到 Activity A 的时候能够通过 onCreate(Bundle) 或者onRestoreInstanceState(Bundle) 来恢复其界面状态。
不要将这个方法和 Activity 生命周期中的回调如 onPause() 或 onStop() 搞混淆了,onPause() 在 Activtiy 被放置到后台或者自行销毁时总会被调用,onStop() 在 Activity 被销毁时被调用。一个会调用 onPause() 和 onStop() 但不会触发 onSaveInstanceState() 的例子是当用户从 Activity B 返回到 Activity A 时:没有必要调用 B 的 onSaveInstanceState(Bundle)方法,因为此时的 B 实例永远不会被恢复,因此系统会避免调用它。一个调用 onPause() 但不调用 onSaveInstanceState(Bundle) 方法的例子是当 Activity B 启动后处在 Activity A 的前端:如果在B的整个生命周期里 A 的用户界面状态都没有被破坏的话,系统是不会调用 Activity A 的onSaveInstanceState(Bundle)方法。
View中也有onSaveInstanceState()来保存view的状态
activity的onSaveInstanceState方法中会调用FragmentManager#saveAllState方法,来进行Fragment的状态保存,同时设置mStateSaved为true,用来标识状态已被保存过.
有两种情况会出现Can not perform this action after onSaveInstanceState异常:
1.FragmentTransaction的commit()时出现:
2.Activity/FragmentActivity的onBackPressed时出现:
这两种情况都是在存储状态后调用了commit或者onBackPressed等方法,这些方法会调用checkStateLoss();抛出异常
private void checkStateLoss() {
if (isStateSaved()) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
}
首先看下commit和commitAllowingStateLoss方法区别:
@Override
public int commit() {
return commitInternal(false);
}
@Override
public int commitAllowingStateLoss() {
return commitInternal(true);
}
commitInternal方法会调用到enqueueAction方法,如果allowStateLoss为false会检查状态,抛出异常;
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
synchronized (this) {
if (mDestroyed || mHost == null) {
if (allowStateLoss) {
// This FragmentManager isn't attached, so drop the entire transaction.
return;
}
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
mPendingActions = new ArrayList<>();
}
mPendingActions.add(action);
scheduleCommit();
}
}
所以,事务要尽早提交,或者使用commitAllowingStateLoss
除此之外,在onBackPressed方法中也会触发checkStateLoss()方法,
比如:Activity/FragmentActivity的onBackPressed时出现
@Override
public void onBackPressed() {
if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {
super.onBackPressed();
}
}
会调用FragmentManagerImpl的popBackStackImmediate()方法,如下:
@Override
public boolean popBackStackImmediate() {
checkStateLoss();
return popBackStackImmediate(null, -1, 0);
}
其实FragmentManagerImpl的popBackStack相关方法基本都有机会触发checkStateLoss();
......前面还有其他popBackStack方法
@Override
public void popBackStack() {
enqueueAction(new PopBackStackState(null, -1, 0), false);
}
@Override
public boolean popBackStackImmediate() {
checkStateLoss();
return popBackStackImmediate(null, -1, 0);
}
@Override
public void popBackStack(@Nullable final String name, final int flags) {
enqueueAction(new PopBackStackState(name, -1, flags), false);
}
@Override
public boolean popBackStackImmediate(@Nullable String name, int flags) {
checkStateLoss();
return popBackStackImmediate(name, -1, flags);
}
enqueueAction方法当boolean allowStateLoss参数传入为false时,就会走checkStateLoss();方法检测存储状态,就有可能抛出异常;
参考:https://blog.csdn.net/liuwei187/article/details/90264751
https://www.cnblogs.com/xhj-records/archive/2013/02/28/2936373.html