一、WindowManager 概述:它到底是什么?
说实话,我刚接触 Android 时,对 WindowManager 也是一头雾水。很多人把它想得很神秘,觉得它是个「窗口管理器」,跟 PC 上的窗口系统差不多。其实不然。
WindowManager,说白了就是 Android 系统里负责「把 View 放到屏幕上」的那个管家。 你写的每个 Activity、Dialog、Toast,甚至输入法、状态栏,最终都要通过它来安排位置、层级、动画。
我个人习惯把它理解成「屏幕空间的调度员」。你想想看,手机屏幕就那么大,那么多界面元素要同时显示,谁在上面谁在下面?谁先响应触摸?谁该被挡住?这些事,都是 WindowManager 在背后默默搞定。
WindowManager 在 Android 系统中的定位
要搞清楚它的定位,得先看看 Android 的系统架构。我画了张图,帮你快速理解:
从这张图你能看到,WindowManager 处在中间层——它连接了上层的应用和下层的显示系统。应用层只管「我要显示什么」,WindowManager 负责「怎么显示、显示在哪」,最后 SurfaceFlinger 负责「真正画到屏幕上」。
关键点:WindowManager 不是直接画图的,它是个「调度者」。真正的绘图工作由 SurfaceFlinger 完成,但 SurfaceFlinger 听谁的?听 WindowManager 的。
WindowManager 的核心职责与作用
我把它归纳为四大职责,这也是我在实际开发中反复打交道的地方:
1. 窗口的添加与移除
这是最基础的功能。每个 View 想要显示到屏幕上,都得通过 WindowManager.addView() 注册。我记得有一次做悬浮球功能,就是因为没处理好 removeView 的时机,导致内存泄漏——嗯,这个坑后面会细讲。
2. 窗口的排序与层级管理
屏幕上那么多窗口,谁盖住谁?这由 Window Type 和 Z-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 的能力来显示界面的。
我画了张关系图,帮你理清:
实际开发中,你什么时候会直接跟 WindowManager 打交道?
说实话,大部分应用开发者不需要直接调用 WindowManager。Activity 和 Dialog 已经帮你封装好了。但以下几种场景,你绕不开它:
- 悬浮窗 / 悬浮球:比如手机管家里的悬浮加速球,必须用
WindowManager.addView()实现 - 全局弹窗:某些系统级提示,需要在所有界面之上显示
- 输入法窗口:输入法本身就是一个系统窗口
- 分屏 / 多窗口:Android 7.0 之后的分屏功能,底层就是 WindowManager 在协调
重要提醒:不要滥用 WindowManager 直接添加窗口。我见过一些开发者为了「省事」,把本该用 Dialog 实现的弹窗,直接用 WindowManager 加了一个系统窗口。结果呢?权限问题、兼容性问题、甚至被应用商店拒审。能用 Activity 或 Dialog 解决的,就别自己造轮子。
小结
这一章我们聊了 WindowManager 是什么、它在系统里的位置、以及它到底管哪些事。说白了,它就是 Android 显示系统的「大管家」——管窗口的添加移除、管层级排序、管事件分发、管动画协调。
下一章,我们会深入 WindowManagerService 的内部,看看它到底是怎么管理这些窗口的。嗯,那里才是真正有意思的地方。
公众号:蓝海资料掘金营,微信deep3321