3. Activity生命周期底层原理
在应用层看来,Activity 的生命周期回调像是系统“自动”调用的;但在底层,每一次 onCreate、onResume、onPause、onDestroy 的背后,都有一条跨越 应用进程 与 system_server 进程 的完整调用链路。理解这条链路,是排查“生命周期错乱”“页面黑屏”“内存泄漏”“启动白屏”等问题的关键。
一、核心角色:ActivityThread、ApplicationThread 与 AMS
Activity 的生命周期并不是由 Activity 自己驱动的,而是由系统服务 ActivityManagerService(AMS)统一调度。AMS 运行在 system_server 进程中,它掌握着所有任务栈、ActivityRecord、进程状态等信息。应用进程侧的核心入口是 ActivityThread,它代表应用的主线程(UI 线程),内部持有 ApplicationThread 这个 Binder 对象,作为 AMS 回调应用进程的“通道”。
- AMS:生命周期调度的决策者,决定某个 Activity 应该处于什么状态。
- ActivityThread:应用进程的主线程管理者,负责实际执行生命周期方法。
- ApplicationThread:AMS 与应用进程之间的 Binder 回调接口,运行在应用进程的 Binder 线程池中。
- ClientTransaction / TransactionExecutor:Android 9 之后引入的事务机制,把“状态请求”和“生命周期执行”解耦。
onCreate。它只是通过 Binder 向应用进程发送“请执行某生命周期”的消息,真正的执行发生在应用主线程的 Handler 消息中。
二、从 launch 到 onCreate:调用链路拆解
当用户点击桌面图标启动一个 Activity 时,大致经历如下链路:
- Launcher 通过
startActivity()请求 AMS 启动目标 Activity。 - AMS 解析 Intent,创建
ActivityRecord,并判断目标进程是否存在。 - 若进程不存在,AMS 先通过
Zygotefork 出新进程,再通知其绑定 Application。 - 进程就绪后,AMS 通过
ApplicationThread向应用进程发送LaunchActivityItem事务。 - 应用进程的 Binder 线程收到事务,将其投递到主线程的
Handler。 - 主线程执行
ActivityThread.handleLaunchActivity(),依次完成performCreate、onStart、onResume。
可以用下面的简化代码理解主线程侧的执行入口:
// ActivityThread 主线程消息处理(简化)
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY:
handleLaunchActivity((ActivityClientRecord) msg.obj);
break;
case PAUSE_ACTIVITY:
handlePauseActivity((IBinder) msg.obj, false, false, 0, null);
break;
case STOP_ACTIVITY:
handleStopActivity((IBinder) msg.obj, false, 0, null);
break;
case DESTROY_ACTIVITY:
handleDestroyActivity((IBinder) msg.obj, false, 0, false);
break;
}
}
可以看到,所有生命周期最终都被转换成主线程消息,按顺序执行。这也是为什么生命周期回调一定运行在主线程,且不能在主线程做耗时操作,否则会阻塞后续生命周期。
三、生命周期状态同步机制:ClientTransaction 事务模型
Android 9(API 28)之后,AMS 与应用进程之间引入了 ClientTransaction 事务模型。AMS 不再逐个发送 PAUSE_ACTIVITY、STOP_ACTIVITY 消息,而是把一组生命周期请求打包成一个事务,由 TransactionExecutor 按顺序执行。
事务模型带来的关键变化:
- 状态请求与执行分离:AMS 只负责生成
ActivityLifecycleItem,应用进程负责执行。 - 顺序保证:事务内部按
onPause → onStop → onDestroy等顺序执行,避免状态跳跃。 - 可合并:短时间内多次状态变化可合并,减少 Binder 通信次数。
- 可追踪:每个事务都有生命周期状态标记,便于系统判断当前 Activity 真实状态。
下面这张图展示了 AMS 与 ActivityThread 之间围绕生命周期状态同步的核心交互关系:
四、典型场景:从 onPause 到 onDestroy 的完整链路
以用户按返回键关闭 Activity 为例,链路如下:
- Activity 调用
finish(),通知 AMS 请求销毁。 - AMS 更新 ActivityRecord 状态,生成包含
PauseActivityItem、StopActivityItem、DestroyActivityItem的事务。 - 事务通过 Binder 下发到应用进程的
ApplicationThread。 - 主线程
TransactionExecutor依次执行onPause → onStop → onDestroy。 - 执行完成后,应用进程向 AMS 回执,AMS 清理 ActivityRecord 并更新任务栈。
onPause 中执行了耗时操作,会阻塞后续 onStop 和 onDestroy,导致上一个页面无法及时显示,出现“点击返回后卡住”的现象。因此 onPause 中只应做轻量级操作。
五、常见误区与复盘
| 误区 | 底层真相 | 正确做法 |
|---|---|---|
| onCreate 由 Activity 自己触发 | 由 AMS 下发事务,ActivityThread 主线程执行 | 不要在 onCreate 中做重耗时初始化 |
| onPause 和 onStop 一定成对出现 | 事务可合并,快速切换时可能跳过 onStop | 状态判断以 onResume/onPause 为准 |
| onDestroy 一定被调用 | 进程被杀时不会回调 onDestroy | 资源释放放在 onStop,而非只依赖 onDestroy |
| 生命周期回调在 Binder 线程执行 | Binder 线程只负责接收,主线程负责执行 | 避免在主线程做耗时操作阻塞生命周期 |
ClientTransaction 批量下发生命周期请求,应用进程通过 TransactionExecutor 顺序执行。若在 onPause 中同步等待网络或数据库,会直接阻塞主线程消息队列,导致后续生命周期无法执行,表现为页面切换卡顿甚至 ANR。
总结来说,Activity 生命周期是 AMS 决策 + Binder 通信 + 主线程消息执行 三者协同的结果。掌握 ActivityThread、ApplicationThread、ClientTransaction 与 TransactionExecutor 之间的分工,就能从底层解释生命周期回调的时序、阻塞与丢失问题,为后续分析启动流程、任务栈和窗口添加打下基础。