Android窗口类型:Z-Order层级管理与跨应用显示

839 阅读3分钟

一、窗口类型:界面的Z-Order层级

Android通过WindowManager.LayoutParams.type为每个窗口分配一个类型值,这个值决定了窗口在屏幕上的Z-Order层级。类型值越大,窗口越靠前,显示在其他窗口之上。

窗口类型类型值范围用途权限
应用窗口1-99Activity、全屏应用无需
子窗口1000-1999DialogPopupWindow、菜单无需,但依赖于父窗口
系统窗口2000+系统UI、悬浮窗、输入法、ToastSYSTEM_ALERT_WINDOW 或系统权限

二、核心类型详解与实践

1. 应用窗口(TYPE_APPLICATION

这是最常见的窗口类型,所有 Activity 窗口都属于这一类型。它们是应用的核心界面,只能显示在它们自己的应用进程中。

  • 用途:承载 Activity 的主界面。
  • 代码:通常由系统在 Activity 启动时自动设置,开发者无需手动干预。

2. 子窗口(TYPE_APPLICATION_PANEL 等)

子窗口不能独立存在,它们必须依附于一个应用窗口。它们的层级高于父窗口,因此可以覆盖父窗口的内容。

  • 用途DialogPopupWindowSpinner 等。

  • 代码

    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_TOASTTYPE_INPUT_METHOD 等)

这些是 Android 系统独有的窗口类型,它们的层级非常高,可以覆盖所有应用窗口。

  • TYPE_TOAST:用于显示短时消息,其层级高于所有应用窗口,但低于输入法。
  • TYPE_INPUT_METHOD:输入法键盘的窗口类型,其层级非常高,可以覆盖几乎所有其他窗口。

三、Z-Order层级关系与核心机制

  • Z-OrderWindowManagerService 负责维护所有窗口的层级关系。当有新的窗口创建时,WindowManagerService 会根据其类型值将其插入到正确的层级。
  • WindowManager:开发者通过 WindowManager 接口,向 WindowManagerService 发送窗口创建、移除和更新的请求。WindowManager 是应用层与系统服务通信的桥梁。
  • SurfaceFlinger:在每个 VSync 信号到来时,SurfaceFlinger 会根据 WindowManagerService 提供的窗口层级信息,将所有可见窗口的 Surface 合成一个完整的画面。

四、开发避坑指南

  1. 悬浮窗权限:在 Android 8.0 及更高版本上,创建悬浮窗需要引导用户到设置页面手动开启权限。
  2. DialogActivity 的关系Dialog 作为一个子窗口,会拦截其父窗口(Activity)的触摸事件。
  3. 内存泄漏:悬浮窗的生命周期独立于 Activity。因此,在不使用时,务必调用 windowManager.removeView() 方法来移除悬浮窗,否则会导致内存泄漏。