一、窗口类型:界面的Z-Order层级
Android通过WindowManager.LayoutParams.type为每个窗口分配一个类型值,这个值决定了窗口在屏幕上的Z-Order层级。类型值越大,窗口越靠前,显示在其他窗口之上。
| 窗口类型 | 类型值范围 | 用途 | 权限 |
|---|---|---|---|
| 应用窗口 | 1-99 | Activity、全屏应用 | 无需 |
| 子窗口 | 1000-1999 | Dialog、PopupWindow、菜单 | 无需,但依赖于父窗口 |
| 系统窗口 | 2000+ | 系统UI、悬浮窗、输入法、Toast | 需 SYSTEM_ALERT_WINDOW 或系统权限 |
二、核心类型详解与实践
1. 应用窗口(TYPE_APPLICATION)
这是最常见的窗口类型,所有 Activity 窗口都属于这一类型。它们是应用的核心界面,只能显示在它们自己的应用进程中。
- 用途:承载
Activity的主界面。 - 代码:通常由系统在
Activity启动时自动设置,开发者无需手动干预。
2. 子窗口(TYPE_APPLICATION_PANEL 等)
子窗口不能独立存在,它们必须依附于一个应用窗口。它们的层级高于父窗口,因此可以覆盖父窗口的内容。
-
用途:
Dialog、PopupWindow、Spinner等。 -
代码:
val dialog = Dialog(context) // Dialog 默认是子窗口,无需手动设置
3. 悬浮窗(TYPE_APPLICATION_OVERLAY)
悬浮窗是一种特殊的系统窗口,它允许应用在所有其他应用之上显示自己的内容。
- 用途:常用于音乐播放器、录屏工具、视频聊天悬浮窗。
- 适配:自 Android 8.0(O)起,
TYPE_APPLICATION_OVERLAY成为开发者创建悬浮窗的唯一选择,它替代了旧的TYPE_SYSTEM_ALERT类型。 - 权限:需要用户手动授权
android.permission.SYSTEM_ALERT_WINDOW权限,以确保用户知情并同意应用在其他应用之上显示内容。
4. 系统窗口(TYPE_TOAST、TYPE_INPUT_METHOD 等)
这些是 Android 系统独有的窗口类型,它们的层级非常高,可以覆盖所有应用窗口。
TYPE_TOAST:用于显示短时消息,其层级高于所有应用窗口,但低于输入法。TYPE_INPUT_METHOD:输入法键盘的窗口类型,其层级非常高,可以覆盖几乎所有其他窗口。
三、Z-Order层级关系与核心机制
- Z-Order:
WindowManagerService负责维护所有窗口的层级关系。当有新的窗口创建时,WindowManagerService会根据其类型值将其插入到正确的层级。 WindowManager:开发者通过WindowManager接口,向WindowManagerService发送窗口创建、移除和更新的请求。WindowManager是应用层与系统服务通信的桥梁。SurfaceFlinger:在每个VSync信号到来时,SurfaceFlinger会根据WindowManagerService提供的窗口层级信息,将所有可见窗口的Surface合成一个完整的画面。
四、开发避坑指南
- 悬浮窗权限:在 Android 8.0 及更高版本上,创建悬浮窗需要引导用户到设置页面手动开启权限。
Dialog与Activity的关系:Dialog作为一个子窗口,会拦截其父窗口(Activity)的触摸事件。- 内存泄漏:悬浮窗的生命周期独立于
Activity。因此,在不使用时,务必调用windowManager.removeView()方法来移除悬浮窗,否则会导致内存泄漏。