一、WindowManager 概述:它到底是什么?

说实话,我刚接触 Android 时,对 WindowManager 也是一头雾水。很多人把它想得很神秘,觉得它是个「窗口管理器」,跟 PC 上的窗口系统差不多。其实不然。

WindowManager,说白了就是 Android 系统里负责「把 View 放到屏幕上」的那个管家。 你写的每个 Activity、Dialog、Toast,甚至输入法、状态栏,最终都要通过它来安排位置、层级、动画。

我个人习惯把它理解成「屏幕空间的调度员」。你想想看,手机屏幕就那么大,那么多界面元素要同时显示,谁在上面谁在下面?谁先响应触摸?谁该被挡住?这些事,都是 WindowManager 在背后默默搞定。

WindowManager 在 Android 系统中的定位

要搞清楚它的定位,得先看看 Android 的系统架构。我画了张图,帮你快速理解:

应用层 (Application Layer) Activity · Dialog · Toast · PopupWindow · 输入法 通过 WindowManager.addView() 请求显示 Framework 层 (WindowManagerService) 核心职责:窗口排序 · 输入事件分发 · 动画协调 运行在 system_server 进程,持有所有窗口信息 SurfaceFlinger 层 (合成与显示) 接收 WindowManager 的窗口层级信息 将各窗口的 Surface 合成后输出到屏幕 硬件层 (显示屏幕)

从这张图你能看到,WindowManager 处在中间层——它连接了上层的应用和下层的显示系统。应用层只管「我要显示什么」,WindowManager 负责「怎么显示、显示在哪」,最后 SurfaceFlinger 负责「真正画到屏幕上」。

关键点:WindowManager 不是直接画图的,它是个「调度者」。真正的绘图工作由 SurfaceFlinger 完成,但 SurfaceFlinger 听谁的?听 WindowManager 的。

WindowManager 的核心职责与作用

我把它归纳为四大职责,这也是我在实际开发中反复打交道的地方:

1. 窗口的添加与移除

这是最基础的功能。每个 View 想要显示到屏幕上,都得通过 WindowManager.addView() 注册。我记得有一次做悬浮球功能,就是因为没处理好 removeView 的时机,导致内存泄漏——嗯,这个坑后面会细讲。

2. 窗口的排序与层级管理

屏幕上那么多窗口,谁盖住谁?这由 Window TypeZ-order 决定。Android 把窗口分成了三类:

类型 层级范围 典型应用
应用窗口 (Application Window) 1 ~ 99 Activity 主界面
子窗口 (Sub Window) 1000 ~ 1999 Dialog、PopupWindow
系统窗口 (System Window) 2000 ~ 2999 状态栏、Toast、输入法

你想想看,为什么 Toast 能显示在 Activity 上面?就是因为它的 type 是 TYPE_TOAST,属于系统窗口,层级比应用窗口高。但这里有个坑——系统窗口需要权限,我曾经在项目里因为忘了加 SYSTEM_ALERT_WINDOW 权限,调试了半天才发现。

3. 输入事件的分发

触摸事件来了,该交给哪个窗口?WindowManager 会根据窗口的层级和位置,计算出命中哪个窗口,然后把事件传过去。这个过程叫 Input Dispatching

避坑指南:我曾经遇到过一个 bug——用户点击屏幕时,事件偶尔会「穿透」到下面的窗口。后来发现是因为窗口的 touchable 区域没设置对。记住:WindowManager 是按矩形区域做命中测试的,如果你的 View 是圆形或异形,得自己处理触摸区域。

4. 窗口动画与过渡

为什么 Activity 切换时有平滑的动画?为什么 Dialog 弹出时有缩放效果?这些动画的协调工作,也是 WindowManager 在管。它维护了一个 动画调度器,确保多个窗口的动画能同步进行。

我个人觉得,动画这部分是最容易出问题的。比如你在一个窗口动画还没结束时,又启动了另一个窗口的动画,就可能出现「卡帧」或「闪白」。嗯,这个我们在后面的「动画协调」章节会深入分析。

WindowManager 与 Activity 的关系

很多人会问:Activity 本身不就是窗口吗?为什么还要 WindowManager?

其实,Activity 不是窗口,它只是一个生命周期容器。每个 Activity 在启动时,会通过 WindowManager.addView() 把它的 DecorView 注册成一个窗口。换句话说,Activity 是「借」WindowManager 的能力来显示界面的。

我画了张关系图,帮你理清:

Activity 生命周期管理 持有 PhoneWindow 实例 创建 PhoneWindow Window 接口实现 持有 DecorView addView WindowManager 窗口注册与管理 最终交给 WMS 调用链:Activity → PhoneWindow → WindowManager → WindowManagerService 注意:每个 Activity 对应一个 PhoneWindow,但一个进程可以 有多个 WindowManager 实例(不同 Context 获取的)

实际开发中,你什么时候会直接跟 WindowManager 打交道?

说实话,大部分应用开发者不需要直接调用 WindowManager。Activity 和 Dialog 已经帮你封装好了。但以下几种场景,你绕不开它:

  • 悬浮窗 / 悬浮球:比如手机管家里的悬浮加速球,必须用 WindowManager.addView() 实现
  • 全局弹窗:某些系统级提示,需要在所有界面之上显示
  • 输入法窗口:输入法本身就是一个系统窗口
  • 分屏 / 多窗口:Android 7.0 之后的分屏功能,底层就是 WindowManager 在协调

重要提醒:不要滥用 WindowManager 直接添加窗口。我见过一些开发者为了「省事」,把本该用 Dialog 实现的弹窗,直接用 WindowManager 加了一个系统窗口。结果呢?权限问题、兼容性问题、甚至被应用商店拒审。能用 Activity 或 Dialog 解决的,就别自己造轮子。

小结

这一章我们聊了 WindowManager 是什么、它在系统里的位置、以及它到底管哪些事。说白了,它就是 Android 显示系统的「大管家」——管窗口的添加移除、管层级排序、管事件分发、管动画协调。

下一章,我们会深入 WindowManagerService 的内部,看看它到底是怎么管理这些窗口的。嗯,那里才是真正有意思的地方。


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