8、Activity 生命周期管理:AMS如何调度onCreate/onStart/onResume/onPause/onStop/onDestroy

生命周期,说白了就是 Activity 从生到死的完整过程。很多开发者觉得这很简单——不就是那几个回调方法吗?嗯,表面上看确实如此。但如果你深入到 AMS 层面,会发现事情远没那么简单。

我个人习惯把生命周期调度比作一场精心编排的舞台剧。AMS 是导演,Activity 是演员,而各种 Binder 调用就是幕后工作人员传递的指令。导演说“该你上场了”,演员才开始表演。今天我们就来拆解一下,AMS 这位导演到底是怎么调度这六场戏的。

8.1 生命周期的“总开关”:LaunchActivityItem

先问一个问题:AMS 怎么通知 App 进程去执行 onCreate

答案是通过 ApplicationThread。AMS 持有 App 进程的 ApplicationThread 代理,通过 Binder 跨进程调用,把生命周期事件“塞”过去。

具体来说,AMS 会构造一个 LaunchActivityItem,然后通过 ClientLifecycleManager 发送给 App 进程。App 进程的主线程 Handler(也就是 ActivityThread.H)收到这个消息后,开始执行真正的生命周期方法。

核心流程:

  • AMS 调用 ActivityStackSupervisor.startSpecificActivityLocked()
  • 检查进程是否存在,不存在则先创建进程
  • 通过 ClientLifecycleManager.scheduleTransaction() 发送事务
  • App 端 ActivityThread.TransactionExecutor.execute() 执行
// AMS 端伪代码
void startSpecificActivityLocked(ActivityRecord r, ...) {
    ProcessRecord app = mService.getProcessRecordLocked(r.processName, ...);
    if (app != null && app.thread != null) {
        // 直接调度生命周期
        realStartActivityLocked(r, app, ...);
    } else {
        // 先启动进程
        mService.startProcessLocked(r.processName, ...);
    }
}

void realStartActivityLocked(ActivityRecord r, ProcessRecord app, ...) {
    // 构造 LaunchActivityItem
    LaunchActivityItem item = new LaunchActivityItem(...);
    // 通过 ClientLifecycleManager 发送
    ClientLifecycleManager.scheduleTransaction(app.thread, item);
}

我曾经在调试一个启动闪退问题时,发现 AMS 发送了 LaunchActivityItem,但 App 进程根本没收到。查了半天,原来是进程被杀后,AMS 持有的 ApplicationThread 代理已经失效了。嗯,这里要注意:AMS 不会主动清理失效的代理,需要你自己在 onServiceDisconnected 里做处理。

8.2 从 onCreate 到 onStart:谁在中间插了一脚?

很多人以为 onCreate 执行完就直接 onStart 了。其实不是。中间 AMS 还做了一件重要的事——窗口添加

流程是这样的:

  1. onCreate 执行完毕,Activity 调用 handleResumeActivity()
  2. handleResumeActivity 中,会调用 WindowManager.addView()
  3. WMS 处理窗口添加,然后回调 AMS 说“窗口准备好了”
  4. AMS 才继续调度 onStartonResume

说白了,onStart 并不是紧跟在 onCreate 后面的。AMS 要等窗口系统确认一切就绪,才会让 Activity 进入“可见”状态。

避坑指南: 我曾经在 onCreate 里做耗时操作,结果导致窗口添加被延迟。用户看到的就是白屏。后来我改成在 onResume 之后才做初始化,体验好多了。

8.3 onResume 的“真假”含义

你想想看,onResume 真的是“恢复”吗?从名字上看是的。但从 AMS 的角度看,onResume 意味着 Activity 已经处于栈顶,并且获得了焦点

AMS 内部有一个 mResumedActivity 变量,指向当前正在前台运行的 Activity。当 AMS 调度 onResume 时,它会:

  • 把当前 Activity 设置为 mResumedActivity
  • 通知 WMS 这个 Activity 获得了焦点
  • 更新 ActivityRecord 的状态为 RESUMED

这里有个细节:AMS 调度 onResume 是异步的。它发送 ResumeActivityItem 后,不会等 App 执行完再返回。所以如果你在 onResume 里做耗时操作,AMS 那边早就认为你已经“恢复”了。

注意: 不要在 onResume 里做超过 5ms 的操作。否则会影响下一个 Activity 的启动速度。我见过一个案例,某应用在 onResume 里做了网络请求,导致页面切换卡顿严重。

8.4 onPause 和 onStop:谁先谁后?

这个问题我面试时经常问。很多人答不上来。其实规则很简单:

  • onPause:当前 Activity 失去焦点时调用(新 Activity 还没完全显示)
  • onStop:当前 Activity 完全不可见时调用(新 Activity 已经覆盖了它)

AMS 的调度顺序是:

  1. 先让旧 Activity onPause
  2. 再启动新 Activity(onCreateonStartonResume
  3. 最后让旧 Activity onStop

为什么会这样?因为 AMS 要保证 新 Activity 尽快显示出来。如果等旧 Activity 完全停止再启动新的,用户会感觉到明显的延迟。

// AMS 调度 onPause 的核心逻辑
void startPausingLocked(ActivityRecord prev, ...) {
    // 发送 PauseActivityItem
    schedulePauseActivity(prev, ...);
    // 等待 App 端执行完毕(有超时机制)
    mService.mHandler.sendMessageDelayed(PAUSE_TIMEOUT_MSG, ...);
}

// App 端执行完 onPause 后回调
void activityPaused(IBinder token) {
    // AMS 收到回调,继续启动新 Activity
    completePauseLocked();
}

我记得有一次线上问题,某个 Activity 的 onPause 里做了数据库写入,导致超时。AMS 等了 500ms 没收到回调,直接强制把 Activity 置为 PAUSED 状态。结果就是——旧 Activity 的状态丢失了。

8.5 onDestroy:最后的告别

onDestroy 是 Activity 的临终遗言。AMS 什么时候会触发它?

  • 用户按返回键(finish() 被调用)
  • 配置变更(如屏幕旋转)导致 Activity 重建
  • 系统内存不足,需要回收 Activity

AMS 调度 onDestroy 时,会发送 DestroyActivityItem。App 端执行完后,会回调 AMS 的 activityDestroyed()。这时 AMS 才会真正从栈中移除这个 ActivityRecord。

关键点: AMS 不会等 onDestroy 执行完才做其他事。它发送指令后就返回了。所以如果你在 onDestroy 里做清理工作,要确保这些工作不会影响其他 Activity 的启动。

8.6 生命周期调度的完整流程图

下面这张图展示了 AMS 调度 Activity 生命周期的完整流程。我建议你仔细看看,尤其是跨进程调用的部分。

AMS 调度 Activity 生命周期流程图 AMS 进程 (System Server) App 进程 ActivityStackSupervisor ClientLifecycleManager ActivityRecord mResumedActivity ActivityThread TransactionExecutor ActivityClientRecord Activity LaunchActivityItem / ResumeActivityItem / PauseActivityItem Binder 回调 (activityPaused/activityResumed) 状态流转: INITIAL → ON_CREATE → ON_START → ON_RESUME → ON_PAUSE → ON_STOP → ON_DESTROY 生命周期方法执行: onCreate → onStart → onResume → onPause → onStop → onDestroy

8.7 生命周期调度的几个关键点

生命周期方法 AMS 发送的事务 App 端执行线程 是否同步等待
onCreate LaunchActivityItem 主线程 否(异步)
onStart (包含在 LaunchActivityItem 中) 主线程
onResume ResumeActivityItem 主线程
onPause PauseActivityItem 主线程 是(有超时)
onStop StopActivityItem 主线程
onDestroy DestroyActivityItem 主线程

注意看 onPause 那一行——它是唯一一个 AMS 会同步等待的方法。为什么?因为 AMS 需要确保旧 Activity 释放了资源(比如相机、传感器),新 Activity 才能正常使用。我曾经遇到一个 bug,某个应用在 onPause 里做了 10 秒的同步网络请求,结果导致整个系统卡死。嗯,后来 Google 在 Android 12 里加了一个限制:onPause 最多只能执行 500ms。

个人建议: 如果你需要做生命周期相关的调试,可以用 adb shell dumpsys activity activities 查看当前所有 Activity 的状态。AMS 会打印每个 ActivityRecord 的 state 字段,比如 RESUMEDPAUSEDSTOPPED 等。这个命令我几乎每天都会用。

最后说一句:生命周期调度看似简单,但 AMS 在背后做了大量的状态管理和跨进程通信工作。理解这些细节,能帮你写出更健壮的应用,也能在遇到疑难问题时快速定位根因。

公众号:蓝海资料掘金营,微信deep3321