Activity 生命周期受其上覆盖的 特定类型控件或窗口 影响,其本质在于 窗口焦点和可见性 的变化。系统通过 WindowManager管理窗口层级,并通过 ActivityThread和 Instrumentation等核心类调度生命周期回调。
下面这个表格汇总了常见控件对 Activity 生命周期的影响,帮助你快速建立整体认知。
| 覆盖物类型 | 典型代表 | 是否影响生命周期 (触发onPause/onStop) | 原因 |
|---|---|---|---|
| Dialog | AlertDialog, DialogFragment | 是 (通常触发 onPause) | 获取焦点,导致原 Activity 失去焦点但仍部分可见 |
| Dialog Theme Activity | 主题为 Theme.AppCompat.Dialog的 Activity | 是 (通常触发 onPause) | 获取焦点,但其窗口层级仍为 Activity 级别,导致原 Activity 失去焦点但仍部分可见 |
| Toast | Toast | 否 | 系统级窗口,不获取焦点,仅作为提示 |
| Status Bar | 通知栏、系统状态栏 | 否 | 系统级窗口,不获取焦点 |
| PopupWindow | - | 否 (但可通过 onWindowFocusChanged 感知) | 默认不获取焦点,不影响生命周期;若设置 setFocusable(true)则会获取焦点并触发 onPause |
💡 如何判断:一个简单的原则是,如果覆盖物会抢夺当前 Activity 的输入焦点(Window Focus),那么就会触发 onPause;如果还完全遮挡了 Activity 使其不可见,则会进一步触发 onStop。
🔍 深入源码:生命周期触发的机制
Android 系统的生命周期回调,核心是由 ActivityThread 通过 H(一个 Handler)处理来自 ActivityManagerService(AMS) 的消息来驱动的。
但窗口焦点和可见性的变化,是触发这些消息的原始信号。
1. 焦点改变如何驱动生命周期
以 Dialog 弹出为例(假设其获取焦点):
-
Dialog 通过
WindowManager.addView()添加窗口。WindowManagerService(WMS) 会计算新的窗口层级,并发现焦点需要转移。 -
WMS 向 AMS 报告焦点变化。AMS 是负责管理所有 Activity 生命周期的“大脑”。
-
AMS 通过 Binder IPC 通知应用进程的
ActivityThread。ActivityThread内部有一个叫H的 Handler,它会收到如PAUSE_ACTIVITY这样的消息。 -
H处理消息,调用handlePauseActivity()。在这个方法里,会依次执行:// ActivityThread.java (简化) private void handlePauseActivity(IBinder token, ...) { ActivityClientRecord r = getActivityRecord(token); // 1. 执行用户熟悉的onPause回调 performPauseActivity(r, ...); // 2. 通知AMS:“我已完成暂停”,AMS随后才会允许新Activity/resume ActivityManager.getService().activityPaused(token); }performPauseActivity方法会通过Instrumentation最终调用到你的 Activity的onPause()方法:// Instrumentation.java public void callActivityOnPause(Activity activity) { activity.performPause(); } -
你的 Activity 的
onPause()被调用。此时 Activity 失去焦点,但通常仍然部分可见(例如 Dialog 后面的界面)。
2. 为何 Toast 和状态栏不影响生命周期?
因为它们的窗口类型是 系统级窗口(如 TYPE_TOAST),不会请求输入焦点。WMS 进行焦点计算时,会跳过这些窗口,当前 Activity 的焦点保持不变,因此 AMS 不会收到需要暂停当前 Activity 的信号,生命周期回调也就不会被触发。
3. 透明Activity的特殊情况
启动一个主题为 Theme.AppCompat.Dialog或设置了透明背景的 Activity (android:windowIsTranslucent=true) 时,虽然它覆盖了整个屏幕,但后面的 Activity 仍然可见。
因此,系统只会触发后面 Activity 的 onPause()(因为它失去了焦点),但不会触发 onStop()(因为它仍然可见)。这就是“只暂停不停止”的特殊场景
。
⚠️ 开发注意事项
-
onPause中应执行轻量级操作:因为onPause执行完成后,新 Activity 的onResume才能被调用,所以这里的耗时操作会直接影响界面切换的流畅度。适合在此释放摄像头、传感器等独占性资源。 -
onStop中可执行重量级操作:此时界面已完全不可见,可以保存用户数据到持久化存储、进行网络请求或执行数据库事务等。 -
利用
onWindowFocusChanged作为补充:有时控件不影响生命周期,但你需要知道窗口焦点的变化(例如视频播放器在弹出非焦点窗口时应暂停)。可以重写onWindowFocusChanged(boolean hasFocus)方法,这是一个很好的辅助监听点。
💎 核心总结
-
•
影响 Activity 生命周期的本质是窗口焦点和可见性的变化,而非简单的视图覆盖。
-
•
AMS 是指挥官,
ActivityThread和H是传令兵和执行官,Instrumentation 是最终调用你代码中生命周期方法的工具。 -
•
Dialog 和 Dialog 主题的 Activity 会抢夺焦点,触发
onPause。 -
•
Toast、状态栏、不获取焦点的 PopupWindow 属于系统级或非焦点窗口,不会影响生命周期。
-
•
理解这套机制,有助于你在合适的生命周期回调中完成正确的操作,从而开发出更流畅、更稳定的应用。
希望这份从应用现象到框架源码的剖析,能让你对 Android 生命周期的理解更加透彻。