Activity 异常生命周期与状态恢复

1. 什么是异常生命周期?

正常生命周期通常由用户操作触发:

打开页面
切换页面
按 Home
按返回键

异常生命周期通常由系统环境变化或资源回收触发:

横竖屏切换
语言切换
深色模式变化
屏幕尺寸变化
字体缩放变化
多窗口尺寸变化
内存不足导致进程被回收

这些情况可能导致 Activity 被销毁并重新创建。


2. 配置变化导致 Activity 重建

没有特殊配置时,横竖屏切换、语言切换、屏幕尺寸变化等都可能导致 Activity 重建。

常见流程可以理解为:

旧 Activity:
onPause()
onStop()
onDestroy()

新 Activity:
onCreate()
onStart()
onResume()

如果系统认为这个 Activity 之后可能被恢复,会触发状态保存:

onSaveInstanceState()

新实例创建时,可以通过:

onCreate(savedInstanceState)
onRestoreInstanceState(savedInstanceState)

恢复之前保存的临时状态。


3. onSaveInstanceState() 的作用

onSaveInstanceState() 用来保存 Activity 被系统临时销毁前的 UI 状态。

示例:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    outState.putString("username", username);
    outState.putInt("pageIndex", pageIndex);
}

适合保存:

输入框临时内容
当前 Tab
列表滚动位置
页面临时筛选条件
当前页码

不适合保存:

大对象
图片 Bitmap
大量列表数据
数据库数据
长期业务状态

原因是 Bundle 需要跨进程传递,数据太大可能造成性能问题,甚至触发异常。


4. 版本差异:onSaveInstanceState() 和 onStop() 顺序

原 PDF 中提到:

onSaveInstanceState() 总是在 onStop() 之前

这个说法只适合早期 Android 行为,不能作为现在的固定结论。

更准确的版本差异如下:

版本 / target 情况 顺序说明
API 28 之前 onSaveInstanceState() 一般在 onStop() 之前;相对 onPause() 的顺序不应强依赖
target API 28+ onSaveInstanceState()onStop() 之后调用

因此不要写依赖强顺序的代码。

更推荐的理解是:

onPause / onStop:处理页面离开前台、不可见相关逻辑
onSaveInstanceState:保存系统重建时需要恢复的临时 UI 状态

5. onSaveInstanceState() 不一定会调用

onSaveInstanceState() 不是普通生命周期方法,不是每次 onPause()onStop() 都一定调用。

典型不会调用或不应依赖的场景:

用户按返回键主动退出 Activity
代码调用 finish()
系统直接杀死整个进程

因为用户主动退出通常表示“不需要恢复这个 Activity”。


6. onRestoreInstanceState() 的作用

onRestoreInstanceState() 用于恢复之前保存的数据。

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    String username = savedInstanceState.getString("username");
    int pageIndex = savedInstanceState.getInt("pageIndex");
}

它一般在:

onStart() 之后
onResume() 之前

被调用。


7. 也可以在 onCreate() 中恢复数据

onCreate() 也有 savedInstanceState 参数:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState != null) {
        String username = savedInstanceState.getString("username");
    }
}

两种方式对比:

方法 特点
onCreate() 每次创建都会调用,所以需要判断 savedInstanceState != null
onRestoreInstanceState() 只有确实存在可恢复状态时才会调用

8. 系统会自动恢复部分 View 状态

Android 会自动保存和恢复部分 View 状态,比如:

EditText 输入内容
ScrollView / RecyclerView / ListView 的部分滚动状态
CheckBox 选中状态

前提通常是:

View 有稳定 id
View 实现了状态保存逻辑
Activity 走了状态保存和恢复流程

所以需要恢复状态的 View,应该设置稳定的 android:id


9. View 状态保存的委托流程

可以理解为:

Activity
  ↓
Window
  ↓
DecorView
  ↓
ViewGroup
  ↓
子 View

Activity 不会亲自保存每个 View 的状态,而是层层委托。

这种委托思想在 Android 里很常见:

View 绘制流程
事件分发流程
View 状态保存流程

10. 内存不足导致 Activity 所在进程被回收

当系统内存不足时,可能杀死低优先级进程。

常见优先级大致是:

前台进程 > 可见进程 > 服务进程 > 后台 / 缓存进程

如果 Activity 已经 onStop(),所在进程更容易被回收。

这时不要指望:

onDestroy() 一定执行

应该把关键状态保存提前做掉。


11. 总结

配置变化重建:用 onSaveInstanceState / onRestoreInstanceState 保存临时 UI 状态
用户主动退出:不要期待 onSaveInstanceState 保存
进程被杀:不要期待 onDestroy 兜底

记忆口诀:

临时状态怕重建,Bundle 保存现场。
关键数据怕丢失,及时落库别等销毁。

参考来源