舞台剧:《Activity的一出好戏》

57 阅读5分钟

咱们就以一场精彩纷呈的“舞台剧”为例,来生动演绎AMS和WMS是如何协同工作,指挥Activity完成生命周期切换的。这场剧的核心角色和场景如下:

角色/场景比喻
​Activity​台上的演员,负责表演(展示UI、处理交互)
​ActivityThread​演员的私人经纪人,负责直接与演员沟通,传达指令和安排行程
​ApplicationThread​经纪人的专用电话接线员(一个Binder对象),负责接收外部来电
​AMS (ActivityManagerService)​总导演,坐在系统进程(system_server)这个后台指挥部里,手握所有剧本和演员调度大权
​WMS (WindowManagerService)​舞台监督,负责管理舞台上的窗口(Window)、灯光、焦点以及观众的视线
​Binder IPC​角色之间高效的对讲机系统
​主线程消息队列 (Looper/Handler)​经纪人手中的日程表,任务按顺序排队处理
​Lifecycle Methods​演员需要执行的不同表演指令(onCreate、onStart等)

现在我们来看一场“从Activity A切换到Activity B”的精彩演出。

🎭 第一幕:换角指令的发出(StartActivity)

    当你在Activity A中点击按钮启动Activity B时,这就像是演员A(当前正在舞台中央)收到了一个指令:让演员B准备上场。

    演员A的经纪人(ActivityThread)通过他的接线员(ApplicationThread)这个​​Binder对讲机​​,紧急联系总导演(​​AMS​​):“导演导演,这里想启动演员B!”

🎬 第二幕:总导演(AMS)的调度

    ​总导演(AMS)​​ 接到电话后,立刻翻看他的全局演员表(​​ActivityStack​​),并进行一系列调度:

    • ​记录在案​​:为演员B创建一个新的档案袋(ActivityRecord)。

    • ​检查场地​​:决定演员B应该在哪个舞台(​​Task​​)上表演,是沿用当前的舞台还是开辟一个新的。

    • ​沟通舞台监督​​:通知​​舞台监督(WMS)​​:“注意,一会儿要有新窗口(Window)上来,灯光和焦点准备调整!”

    • ​下达暂停指令​​:最重要的第一步是,导演通过对讲机告诉经纪人A的接线员:“先让演员A暂停表演!”(schedulePauseActivity) 。

📞 第三幕:经纪人(ActivityThread)安排工作

    经纪人A的接线员(ApplicationThread)接到导演的“暂停”电话后,经纪人(ActivityThread)并不会立刻直接告诉演员A。他会把“让演员A执行onPause”这个任务写进自己的​​日程表(主线程消息队列,Handler H)​​ 里排队,等待执行 。

    轮到执行这个任务时,经纪人会通过一位助手(Instrumentation)正式通知演员A:“导演让你做暂停动作了”。于是,演员A开始执行onPause()方法 。

🔄 第四幕:闭环反馈与新一轮调度

    演员A的onPause()表演一完成,经纪人A立刻通过对讲机反向通知总导演AMS:“报告导演,演员A已暂停!”

    ​总导演(AMS)​​ 收到这个反馈信号后,确认了第一步已完成。于是开始第二步调度,再次通过对讲机呼叫演员B所在应用的接线员(如果进程不存在,AMS会先联系Zygote孵化一个新进程和新经纪人):“现在准备启动演员B,这是他的剧本(Intent)和之前保存的状态(Bundle)!”(scheduleLaunchActivity) 。

🎪 第五幕:新演员的登场与就位(生命周期执行)

    演员B的经纪人(ActivityThread)收到导演的“启动”指令后,同样地将“启动演员B”这个任务放入日程表排队。

    任务执行时,经纪人会:

    • ​找演员​​:通过反射找到演员B,并把他请到后台(newActivity)。

    • ​给剧本​​:为演员B搭建基本的化妆间和道具间(创建ContextImpl,调用activity.attach())。

    • ​初次彩排​​:助手(Instrumentation)通知演员B:“这是你的初始剧本,请开始你的第一次彩排(onCreate)!”——演员B开始执行onCreate(),加载UI布局 。

    • ​登台准备​​:助手继续通知:“请到侧台准备(onStart)!”——演员B执行onStart(),此时观众可能还看不到他。

    • ​请求焦点​​:经纪人同时联系​​舞台监督(WMS)​​:“我们演员B的舞台布景(View树)好了,请给他打灯光、分配一个Surface(画布)!”

    ​舞台监督(WMS)​​ 为演员B的窗口安排好位置、层级,并准备好画布(Surface)。一切就绪后,通知经纪人。

    经纪人最后通知演员B:“现在,请走到舞台中央,开始你的表演吧!(onResume)”——演员B执行onResume(),完全进入前台,获得焦点,正式与观众交互 。

📋 生命周期调用顺序总结

场景生命周期调用顺序
​正常启动新Activity​onPause(A)-> onCreate(B)-> onStart(B)-> onResume(B)-> onStop(A)(如果A完全不可见)
​返回上一个Activity​onPause(B)-> onRestart(A)-> onStart(A)-> onResume(A)-> onStop(B)-> onDestroy(B)(如果B被 finish)
​配置变化(如旋转)​onPause-> onSaveInstanceState-> onStop-> onDestroy-> onCreate-> onStart-> onRestoreInstanceState-> onResume

💡 核心要点

  • ​感知靠指挥​​:AMS并​​不是“感知”​​到生命周期的变化,而是作为​​总导演​​,​​主动发起和调度​​所有这些生命周期方法的调用。它通过Binder IPC机制向应用进程发送指令 。

  • ​执行在本地​​:生命周期方法的具体执行,发生在你的应用进程的​​主线程​​中,由ActivityThreadInstrumentation根据AMS的指令来调用 。这就是为什么在生命周期方法里做耗时操作会卡顿甚至ANR。

  • ​协作是关键​​:​​WMS(舞台监督)​​ 负责管理窗口、Surface和焦点,与​​AMS(总导演)​​ 紧密配合。AMS决定“谁该上场”,WMS则负责“如何把上场演员的窗口展示好” 。

  • ​消息队列是核心​​:从AMS发来的指令是通过Binder线程收到的,但最终都被发送到主线程的​​消息队列(Message Queue)​​ 中,由​​Handler H​​逐个处理,从而保证了所有生命周期方法都在主线程中顺序执行 。

希望这场“舞台剧”能帮助你直观地理解AMS和WMS是如何协同工作,指挥Activity生命周期的。