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 之后引入的事务机制,把“状态请求”和“生命周期执行”解耦。
关键点:AMS 不会直接调用 Activity 的 onCreate。它只是通过 Binder 向应用进程发送“请执行某生命周期”的消息,真正的执行发生在应用主线程的 Handler 消息中。

二、从 launch 到 onCreate:调用链路拆解

当用户点击桌面图标启动一个 Activity 时,大致经历如下链路:

  1. Launcher 通过 startActivity() 请求 AMS 启动目标 Activity。
  2. AMS 解析 Intent,创建 ActivityRecord,并判断目标进程是否存在。
  3. 若进程不存在,AMS 先通过 Zygote fork 出新进程,再通知其绑定 Application。
  4. 进程就绪后,AMS 通过 ApplicationThread 向应用进程发送 LaunchActivityItem 事务。
  5. 应用进程的 Binder 线程收到事务,将其投递到主线程的 Handler。
  6. 主线程执行 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 之间围绕生命周期状态同步的核心交互关系:

AMS 与 ActivityThread 生命周期状态同步链路 system_server 进程 ActivityManagerService 管理 ActivityRecord / 任务栈 / 进程状态 ClientTransaction 打包 Launch / Pause / Stop / Destroy 请求 IApplicationThread (Binder) 跨进程调用应用侧 ApplicationThread 状态决策:RESUMED / PAUSED / STOPPED 应用进程 ApplicationThread Binder 线程池接收 AMS 事务 ActivityThread (主线程) Handler 消息队列顺序执行 TransactionExecutor 按顺序执行生命周期 Item Activity: onCreate → onStart → onResume Binder 调用 状态回执 / 完成通知 AMS 决策状态 → Binder 下发事务 → 主线程顺序执行 → 回执同步状态

四、典型场景:从 onPause 到 onDestroy 的完整链路

以用户按返回键关闭 Activity 为例,链路如下:

  1. Activity 调用 finish(),通知 AMS 请求销毁。
  2. AMS 更新 ActivityRecord 状态,生成包含 PauseActivityItem、StopActivityItem、DestroyActivityItem 的事务。
  3. 事务通过 Binder 下发到应用进程的 ApplicationThread。
  4. 主线程 TransactionExecutor 依次执行 onPause → onStop → onDestroy。
  5. 执行完成后,应用进程向 AMS 回执,AMS 清理 ActivityRecord 并更新任务栈。
如果 onPause 中执行了耗时操作,会阻塞后续 onStop 和 onDestroy,导致上一个页面无法及时显示,出现“点击返回后卡住”的现象。因此 onPause 中只应做轻量级操作。

五、常见误区与复盘

误区 底层真相 正确做法
onCreate 由 Activity 自己触发 由 AMS 下发事务,ActivityThread 主线程执行 不要在 onCreate 中做重耗时初始化
onPause 和 onStop 一定成对出现 事务可合并,快速切换时可能跳过 onStop 状态判断以 onResume/onPause 为准
onDestroy 一定被调用 进程被杀时不会回调 onDestroy 资源释放放在 onStop,而非只依赖 onDestroy
生命周期回调在 Binder 线程执行 Binder 线程只负责接收,主线程负责执行 避免在主线程做耗时操作阻塞生命周期
特别注意:Android 9 之后,AMS 通过 ClientTransaction 批量下发生命周期请求,应用进程通过 TransactionExecutor 顺序执行。若在 onPause 中同步等待网络或数据库,会直接阻塞主线程消息队列,导致后续生命周期无法执行,表现为页面切换卡顿甚至 ANR。

总结来说,Activity 生命周期是 AMS 决策 + Binder 通信 + 主线程消息执行 三者协同的结果。掌握 ActivityThread、ApplicationThread、ClientTransaction 与 TransactionExecutor 之间的分工,就能从底层解释生命周期回调的时序、阻塞与丢失问题,为后续分析启动流程、任务栈和窗口添加打下基础。