Appearance
Android 生命周期总览
Android 生命周期的核心不是“页面开了关了”这么简单,而是 可见性、可交互性、进程存活、配置变更恢复 四条线交织在一起。
代码索引
| 主题 | Lab 说明 | 源码 |
|---|---|---|
| Activity 基础生命周期顺序(Kotlin + XML) | android-activity-lifecycle-basic | LifecycleLogActivity.kt · ActivityDetailActivity.kt |
| Activity 生命周期 + Compose 组合树进入/退出 | android-activity-lifecycle-compose | ComposeLifecycleActivity.kt |
| Activity 基础生命周期顺序(Java + XML) | android-activity-lifecycle-java-xml | JavaLifecycleActivity.java |
为什么需要
很多线上问题表面是“页面问题”,本质其实是生命周期问题:
- 页面返回后数据为什么丢了
- 进后台回来为什么又请求一次
- 横竖屏切换为什么页面重建
- 页面 A 打开 B 时,A 到底什么时候不可交互、什么时候不可见
- 为什么某些回调写在
onCreate没问题,写在onResume就会重复触发
底层机制
1. Activity 生命周期不是单一开关
最常见顺序:
text
onCreate
→ onStart
→ onResume
→ onPause
→ onStop
→ onDestroy但真实运行里还经常出现:
text
onRestart → onStart → onResume这说明:
- 一个 Activity 离开前台后,不一定立刻销毁
- 返回时也不一定重新
onCreate - 生命周期与“实例是否还活着”强相关
2. 可见 ≠ 可交互
onResume:通常表示进入前台、可以交互onPause:失去前台焦点onStop:通常已不可见
所以很多资源释放与暂停逻辑,不能只凭“用户看不看得到”做判断。
3. 生命周期还受配置变更与进程回收影响
例如:
- 旋转屏幕
- 深色模式变化
- 语言变化
- 后台进程被系统回收
这类场景会让 Activity 重建,但业务往往要求状态看起来“没断”。这就是为什么还要配合:
ViewModelSavedStateHandle- 持久化缓存
Android / Flutter / Web / Backend 对照
| 维度 | Android | Flutter | Web | Backend |
|---|---|---|---|---|
| 页面创建 | onCreate | initState | 组件 mount / 首次 render | 请求进入 handler |
| 可交互 | onResume | 页面进入前台可操作 | DOM 可交互 | 请求处理中 |
| 暂失焦点 | onPause | 路由覆盖 / App 状态变化 | tab 失焦 / 遮挡 | 无直接对应 |
| 不可见 | onStop | 页面在栈中但不在前台 | 路由离开 / 被缓存 | 无 UI 栈 |
| 销毁 | onDestroy | dispose | unmount | 请求结束 / 对象释放 |
常见场景
1. 页面 A 打开页面 B
典型顺序:
- A:
onPause - B:
onCreate → onStart → onResume - A:若完全被遮住,通常再到
onStop
返回时:
- B:
onPause → onStop → onDestroy - A:
onRestart → onStart → onResume
对应 Lab:android-activity-lifecycle-basic · LifecycleLogActivity.kt · ActivityDetailActivity.kt · android-activity-lifecycle-compose · ComposeLifecycleActivity.kt · android-activity-lifecycle-java-xml · JavaLifecycleActivity.java
2. 页面返回后重复刷新
如果把“每次可交互都刷新”写在 onResume,那么:
- 首次打开会跑
- 从详情页返回会再跑
- 某些权限弹窗回来也会再跑
所以要分清:
- 一次性初始化
- 每次回前台刷新
- 仅在特定结果返回时刷新
3. 横竖屏切换与状态丢失
Activity 可能被销毁重建。若状态只放在 View 里,常常直接丢失。
常见坑
| 坑 | 现象 | 修法 |
|---|---|---|
在 onResume 放所有加载逻辑 | 每次返回页面都重复执行 | 区分首次初始化与回前台刷新 |
以为 onPause 后页面就完全不可见 | 部分场景仍可见 | 资源降级/暂停要看具体阶段 |
| 把状态只放在 Activity 字段里 | 旋转或系统回收后丢失 | 用 ViewModel / SavedStateHandle / 持久化 |
| 误把生命周期顺序当固定死板模板 | 某些系统/多窗口场景表现不同 | 用日志验证具体场景 |
与相近概念对比
| 概念 | 关注点 | 适合处理的问题 |
|---|---|---|
onCreate | 初始创建 | inflate、一次性绑定、首次 setup |
onStart | 即将可见 | 可见前准备 |
onResume | 前台可交互 | 恢复输入、动画、页面交互 |
onPause | 失去前台焦点 | 暂停相机、动画、轻量资源 |
onStop | 不可见 | 释放更重资源、停止 UI 相关工作 |
onDestroy | 最终销毁 | 最后清理,但不能假设一定总能执行 |
对应实验
各章节内已嵌入跳转链接;此处汇总全部 Lab:
| Lab | 说明 | 源码 |
|---|---|---|
| android-activity-lifecycle-basic | android-activity-lifecycle-basic | LifecycleLogActivity.kt · ActivityDetailActivity.kt |
| android-activity-lifecycle-compose | android-activity-lifecycle-compose | ComposeLifecycleActivity.kt |
| android-activity-lifecycle-java-xml | android-activity-lifecycle-java-xml | JavaLifecycleActivity.java |
复习检查题
为什么
onResume里的逻辑要格外谨慎?答:因为首次进入、从详情页返回、权限弹窗回来、回到前台等多个场景都会触发
onResume,若把昂贵逻辑全放这里,很容易重复执行。onPause和onStop的关键区别是什么?答:
onPause更接近“失去前台焦点、不可交互”,onStop更接近“已不可见”;因此轻量暂停与重资源释放通常分布在两个阶段。为什么不能只靠 Activity 成员变量保存页面状态?
答:因为配置变更或进程回收后 Activity 可能重建,纯内存字段会丢;需要用
ViewModel、SavedStateHandle或持久化层兜底。
速记
onCreate:建实例onResume:前台可交互onPause:失焦onStop:不可见onDestroy:最终销毁但不保证总能观察到