WMS 窗口管理
问题
Android 的窗口管理系统是如何工作的?Window、WindowManager、Surface 之间是什么关系?
答案
核心概念关系
Window 类型
| 类型 | 层级(z-order) | 示例 |
|---|---|---|
| Application Window | 1~99 | Activity 窗口 |
| Sub Window | 1000~1999 | Dialog、PopupWindow |
| System Window | 2000~2999 | Toast、StatusBar、导航栏 |
层级越高,显示越靠前。
View 绘制流程
measure:递归遍历 View 树,每个 View 根据 MeasureSpec 计算自身宽高
layout:父 View 根据子 View 的测量结果确定其在父容器中的位置
draw:Canvas 绘制背景、内容(onDraw)、子 View、前景
DecorView 结构
PhoneWindow
└── DecorView (FrameLayout)
├── StatusBar Background
├── LinearLayout
│ ├── ActionBar / Toolbar
│ └── ContentFrameLayout (android.R.id.content)
│ └── 你的布局 (setContentView)
└── NavigationBar Background
常见面试问题
Q1: Dialog 必须依附于 Activity 的 Context 原因是什么?
答案:
Dialog 默认创建的是 Sub Window(子窗口),子窗口必须附属于一个父窗口(Application Window)。Activity 的 Context 中持有 Activity 的 Window Token,Dialog 通过它关联到 Activity 的窗口。如果使用 Application Context,没有 Window Token,会抛出 WindowManager$BadTokenException。
Q2: Window 和 Surface 的区别?
答案:
- Window:逻辑概念,代表一个矩形显示区域,由 WMS 管理其位置、大小和层级
- Surface:实际的图形缓冲区,View 树绘制的内容最终渲染到 Surface 上
- SurfaceFlinger:系统服务,将所有 Surface 合成为最终的帧输出到屏幕
简单来说,Window 管理"在哪里显示",Surface 管理"显示什么内容"。
Q3: requestLayout 和 invalidate 的区别?
答案:
| 方法 | 触发 measure | 触发 layout | 触发 draw |
|---|---|---|---|
requestLayout() | ✅ | ✅ | 可能 |
invalidate() | ❌ | ❌ | ✅ |
- 修改 View 尺寸或位置 →
requestLayout() - 只改变外观(颜色、文字)→
invalidate()