深入浅出讲解安卓WMS(Window Manager Service)
WMS(Window Manager Service,窗口管理服务)是Android系统中负责管理所有窗口(Window)的核心服务。它决定了哪个窗口显示在最前面、如何布局、怎样处理触摸事件,就像是一个窗口调度员。
一、WMS是干什么的?
想象你的手机屏幕是一个大舞台,WMS就是舞台导演,负责:
- 窗口的显示与隐藏(比如:弹窗、Activity、输入法、状态栏)
- 窗口的层级(Z-order)(谁在上面,谁在下面)
- 窗口的尺寸和位置(比如分屏、悬浮窗)
- 触摸事件的分发(点哪里?交给谁处理?)
- 动画和过渡效果(比如Activity切换动画)
二、WMS管理哪些窗口?
Android的窗口主要分为几类:
| 窗口类型 | 示例 | 特点 |
|---|---|---|
| 应用窗口(Application Window) | Activity、Dialog | 普通App的界面 |
| 子窗口(Sub Window) | PopupWindow、菜单 | 必须依附于某个父窗口 |
| 系统窗口(System Window) | 状态栏、Toast、输入法 | 全局显示,不受Activity限制 |
| 悬浮窗(Floating Window) | 悬浮球、小窗模式 | 可以叠加在其他窗口上 |
三、WMS的核心工作原理
1. 窗口的添加与移除
- 添加窗口:当Activity启动时,WMS会:
- 分配一个Surface(绘制的画布)
- 计算窗口的位置和大小
- 决定它的Z轴顺序(谁盖住谁?)
- 移除窗口:当Activity关闭时,WMS会:
- 释放对应的Surface
- 调整其他窗口的布局(比如输入法退出后,界面要重新调整)
2. 窗口的层级(Z-order)
WMS用Z-order决定窗口的显示顺序,比如:
- 系统窗口(如状态栏) 通常在最顶层(Z轴值最大)
- 普通Activity窗口 在中间层
- 壁纸(Wallpaper) 在最底层
3. 触摸事件的分发
当你点击屏幕:
- InputManager 收到触摸事件
- WMS 根据窗口的Z-order,找到最顶层的窗口
- WMS 把事件交给对应的窗口处理(比如Activity或Dialog)
4. 窗口动画
Activity切换、Dialog弹出时的动画,也是由WMS控制的:
- WMS 告诉SurfaceFlinger(负责合成的系统服务)如何做动画
- 比如:平移、缩放、淡入淡出
四、WMS与其他服务的关系
WMS不是孤立的,它和其他系统服务紧密配合:
| 服务 | 交互方式 | 作用 |
|---|---|---|
| AMS(Activity Manager) | 通过Binder通信 | AMS告诉WMS哪个Activity要显示 |
| SurfaceFlinger | 通过Surface控制 | WMS管理窗口的绘制缓冲区 |
| InputManager | 事件传递 | WMS决定触摸事件交给谁 |
五、开发者需要关注的WMS问题
1. 窗口类型的选择
- 普通Activity用
TYPE_APPLICATION - 全局弹窗用
TYPE_APPLICATION_OVERLAY(需要悬浮窗权限) - 系统Alert用
TYPE_SYSTEM_ALERT(已废弃,Android 8.0+受限)
2. 窗口层级调整
WindowManager.LayoutParams params = getWindow().getAttributes();
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
params.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
getWindow().setAttributes(params);
3. 悬浮窗权限
Android 8.0+必须申请:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
并在代码中动态请求:
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(intent);
}
4. 窗口焦点问题
- 如果弹窗抢了焦点,可以加
FLAG_NOT_FOCUSABLE - 输入法弹出时,WMS会自动调整窗口,避免被遮挡
六、WMS的常见问题
1. 为什么我的Dialog不显示?
- 可能没设置正确的
WindowManager.LayoutParams - 可能缺少悬浮窗权限(Android 8.0+)
2. 为什么点击事件穿透了?
- 检查窗口的
FLAG_NOT_TOUCHABLE或FLAG_NOT_FOCUSABLE - 可能是Z-order设置错误,导致事件被上层窗口拦截
3. 为什么Activity切换卡顿?
- WMS在计算窗口动画和布局
- 可能是
onCreate()太耗时,导致WMS等待
总结
- WMS是Android的窗口大管家,负责管理所有窗口的显示、层级、触摸事件。
- 窗口类型决定它的行为(普通窗口、系统窗口、悬浮窗)。
- Z-order决定谁在上面,谁在下面。
- 触摸事件由WMS决定分发给哪个窗口。
- 开发者要注意窗口权限、层级、焦点,避免出现显示或交互问题。
理解WMS,能让你更好地处理UI显示、弹窗、触摸事件等问题! 🚀