protected void onSaveInstanceState (Bundle outState)
在 Activity 可能被 kill 之前调用,保存每个实例的状态,使它们可以在 onCreate(Bundle) 或 onRestoreInstanceState(Bundle) 方法中恢复(outState 会传给这两个方法)。
比如,A 启动了 B,A 不可见了,A 就会通过执行这个方法来保存当前的信息,然后系统 kill A 来回收资源,当 B 返回到 A,A 会通过 onCreate(Bundle) 或 onRestoreInstanceState(Bundle) 来恢复信息。
该方法与 onPause()、onStop() 没有直接关系。
假设 A 是一个普通的 Activity,B 是一个透明的 Activity。
- A 启动 B,B 返回 A,B 的 onPause()、onStop() 调用了,但 onSaveInstanceState() 没有调用,因为 B 的实例不会被恢复。
- A 启动 B,如果 A 没有被系统杀死,A 的 onPause() 调用了, 但 onSaveInstanceState() 不会被调用,因为 A 的界面没有被回收。
在 android P(28) 后,该方法会在 onStop() 后执行,但在 P 之前,它会在 onStop() 之前执行,不确定在 onPause() 之前还是之后执行。
activity 可能会被系统 kill 掉的情况,包括但不限于:
(1)A 在前台,在某个时刻系统因为回收资源的问题要 kill A 时,A 会调用该方法;
(2)从 A 回到桌面;
(3)从 A 锁屏;
(4)A 横竖屏切换时;
(5)A 启动 B,B 在前台,A 不可见时,A 会调用该方法;
(6)A 启动 B,B 在前台,A 仍可见,在某个时刻系统因为回收资源的问题要 kill B 时,B 会调用该方法。
总之,在 stop 执行之前,系统判断是否需要再回到该界面(用户手动退出kill的不需要,系统回收资源kill的则需要),如果需要,就会执行 onSaveInstanceState() 方法。
bug(sdk 23):
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager:1884)
at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager:783)
at android.support.v4.app.FragmentActivity.onBackPressed(FragmentActivity:178)
这个问题的原因是,在按返回键的时候,instanceState 被 save 过了,但还没有被 restore。super.onBackPressed() 里会对 save 的状态进行判断。
解决方案:
// 有问题的写法
@Override
public void onBackPressed() {
super.onBackPressed();
......
}
// 改法1
// 去掉 super
@Override
public void onBackPressed() {
......
}
// 改法2
// 在 super 之前加上 onStateNotSaved,将 saved 状态置为 false
@Override
public void onBackPressed() {
onStateNotSaved();
super.onBackPressed();
......
}
// 改法3
// 修改 onSaveInstanceState 方法,使 saved 状态置为 false
@Override
protected void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
onStateNotSaved();
}
bug(sdk 23):
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1884)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1902)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:650)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:609)
这个问题的原因是,在 commit 的时候,instanceState 被 save 过了,但还没有被 restore。commit() 里会对 save 的状态进行判断。
解决方案:
同上,在调用 commit 的方法里,加上 onStateNotSaved()。