1475 lines
22 KiB
Markdown
1475 lines
22 KiB
Markdown
# WMS窗口常见面试题
|
||
|
||
|
||
|
||
本文档整理了Android WMS(Window Manager Service)窗口管理相关的常见面试题,涵盖基础概念、架构原理、源码分析、问题排查等多个方面。
|
||
|
||
|
||
|
||
## 目录
|
||
|
||
|
||
|
||
- [基础概念类](#基础概念类)
|
||
|
||
- [架构原理类](#架构原理类)
|
||
|
||
- [窗口管理类](#窗口管理类)
|
||
|
||
- [源码分析类](#源码分析类)
|
||
|
||
- [性能优化类](#性能优化类)
|
||
|
||
- [问题排查类](#问题排查类)
|
||
|
||
- [多窗口相关](#多窗口相关)
|
||
|
||
|
||
|
||
---
|
||
|
||
|
||
|
||
## 基础概念类
|
||
|
||
|
||
|
||
### Q1: 什么是WMS?它的主要职责是什么?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
WMS(Window Manager Service)是Android窗口系统的核心服务,运行在system_server进程中。
|
||
|
||
|
||
|
||
**主要职责:**
|
||
|
||
|
||
|
||
1. **窗口管理**:管理所有窗口的创建、显示、销毁等生命周期
|
||
|
||
2. **窗口层级管理**:维护窗口的Z-Order顺序,决定窗口的显示优先级
|
||
|
||
3. **布局计算**:计算窗口的位置、大小和可见区域
|
||
|
||
4. **输入事件分发**:将触摸、按键等输入事件分发给正确的窗口
|
||
|
||
5. **窗口动画**:管理窗口的显示、隐藏、切换等动画效果
|
||
|
||
6. **屏幕旋转**:处理屏幕方向变化时的窗口布局调整
|
||
|
||
7. **多显示支持**:支持多个显示设备的窗口管理
|
||
|
||
|
||
|
||
```java
|
||
|
||
// WMS是系统服务,在SystemServer中启动
|
||
|
||
public class SystemServer {
|
||
|
||
private void startOtherServices(...) {
|
||
|
||
WindowManagerService wm = WindowManagerService.main(...);
|
||
|
||
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
### Q2: WMS与WindowManager、WindowManagerGlobal的关系是什么?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
这三者的关系如下:
|
||
|
||
|
||
|
||
1. **WindowManager**:应用层接口,开发者使用的API
|
||
|
||
2. **WindowManagerGlobal**:应用层实现,管理ViewRootImpl和窗口会话
|
||
|
||
3. **WindowManagerService**:系统服务,实际管理窗口的服务端
|
||
|
||
|
||
|
||
**调用流程:**
|
||
|
||
|
||
|
||
```
|
||
|
||
应用层:WindowManager.addView()
|
||
|
||
↓
|
||
|
||
WindowManagerGlobal.addView()
|
||
|
||
↓
|
||
|
||
ViewRootImpl.setView()
|
||
|
||
↓
|
||
|
||
IWindowSession.addToDisplay() (Binder调用)
|
||
|
||
↓
|
||
|
||
WMS.addWindow() (服务端)
|
||
|
||
```
|
||
|
||
|
||
|
||
```java
|
||
|
||
// WindowManager接口
|
||
|
||
public interface WindowManager extends ViewManager {
|
||
|
||
void addView(View view, ViewGroup.LayoutParams params);
|
||
|
||
void removeView(View view);
|
||
|
||
void updateViewLayout(View view, ViewGroup.LayoutParams params);
|
||
|
||
}
|
||
|
||
|
||
|
||
// WindowManagerGlobal实现
|
||
|
||
public final class WindowManagerGlobal {
|
||
|
||
public void addView(View view, ViewGroup.LayoutParams params, ...) {
|
||
|
||
ViewRootImpl root = new ViewRootImpl(view.getContext(), display);
|
||
|
||
root.setView(view, wparams, panelParentView);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
// WMS服务端
|
||
|
||
public class WindowManagerService {
|
||
|
||
public int addWindow(Session session, IWindow client, ...) {
|
||
|
||
// 实际窗口管理逻辑
|
||
|
||
}
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
### Q3: 窗口类型有哪些?它们的层级关系是什么?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**窗口类型:**
|
||
|
||
|
||
|
||
1. **应用窗口(APPLICATION)**
|
||
|
||
- `TYPE_APPLICATION`:普通Activity窗口
|
||
|
||
- `TYPE_APPLICATION_STARTING`:启动窗口
|
||
|
||
- `TYPE_BASE_APPLICATION`:应用基础窗口
|
||
|
||
|
||
|
||
2. **子窗口(SUB_WINDOW)**
|
||
|
||
- `TYPE_APPLICATION_PANEL`:应用面板
|
||
|
||
- `TYPE_APPLICATION_SUB_PANEL`:应用子面板
|
||
|
||
- `TYPE_APPLICATION_ATTACHED_DIALOG`:附加对话框
|
||
|
||
|
||
|
||
3. **系统窗口(SYSTEM_WINDOW)**
|
||
|
||
- `TYPE_STATUS_BAR`:状态栏
|
||
|
||
- `TYPE_NAVIGATION_BAR`:导航栏
|
||
|
||
- `TYPE_SYSTEM_ALERT`:系统警告窗口
|
||
|
||
- `TYPE_TOAST`:Toast窗口
|
||
|
||
- `TYPE_APPLICATION_OVERLAY`:悬浮窗(需要权限)
|
||
|
||
|
||
|
||
**层级关系(Z-Order):**
|
||
|
||
|
||
|
||
```
|
||
|
||
系统窗口(最高)
|
||
|
||
↓
|
||
|
||
应用窗口(中等)
|
||
|
||
↓
|
||
|
||
子窗口(最低)
|
||
|
||
```
|
||
|
||
|
||
|
||
```java
|
||
|
||
// 窗口类型定义
|
||
|
||
public static class LayoutParams {
|
||
|
||
// 应用窗口:1000-1999
|
||
|
||
public static final int TYPE_APPLICATION = 2;
|
||
|
||
public static final int TYPE_APPLICATION_STARTING = 3;
|
||
|
||
// 子窗口:1000-1999
|
||
|
||
public static final int TYPE_APPLICATION_PANEL = 1000;
|
||
|
||
// 系统窗口:2000-2999
|
||
|
||
public static final int TYPE_STATUS_BAR = 2000;
|
||
|
||
public static final int TYPE_SYSTEM_ALERT = 2003;
|
||
|
||
public static final int TYPE_TOAST = 2005;
|
||
|
||
public static final int TYPE_APPLICATION_OVERLAY = 2038;
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
---
|
||
|
||
|
||
|
||
## 架构原理类
|
||
|
||
|
||
|
||
### Q4: WMS的架构是怎样的?包含哪些核心组件?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**WMS架构分层:**
|
||
|
||
|
||
|
||
```
|
||
|
||
┌─────────────────────────────────┐
|
||
|
||
│ 应用层(客户端) │
|
||
|
||
│ Activity/WindowManager │
|
||
|
||
└──────────────┬──────────────────┘
|
||
|
||
│ Binder IPC
|
||
|
||
┌──────────────▼──────────────────┐
|
||
|
||
│ 系统服务层(服务端) │
|
||
|
||
│ WindowManagerService │
|
||
|
||
│ ├── WindowState │
|
||
|
||
│ ├── DisplayContent │
|
||
|
||
│ ├── WindowToken │
|
||
|
||
│ └── WindowAnimator │
|
||
|
||
└──────────────┬──────────────────┘
|
||
|
||
│
|
||
|
||
┌──────────────▼──────────────────┐
|
||
|
||
│ 显示层 │
|
||
|
||
│ SurfaceFlinger │
|
||
|
||
└─────────────────────────────────┘
|
||
|
||
```
|
||
|
||
|
||
|
||
**核心组件:**
|
||
|
||
|
||
|
||
1. **WindowManagerService**:WMS主类,管理所有窗口
|
||
|
||
2. **WindowState**:窗口状态,表示一个窗口的所有信息
|
||
|
||
3. **DisplayContent**:显示内容,管理一个显示设备上的所有窗口
|
||
|
||
4. **WindowToken**:窗口令牌,用于窗口分组和权限控制
|
||
|
||
5. **WindowAnimator**:窗口动画控制器
|
||
|
||
6. **WindowStateAnimator**:单个窗口的动画状态
|
||
|
||
|
||
|
||
```java
|
||
|
||
// WindowState:窗口状态
|
||
|
||
class WindowState {
|
||
|
||
final WindowManagerService mService;
|
||
|
||
final WindowToken mToken;
|
||
|
||
final WindowManager.LayoutParams mAttrs;
|
||
|
||
final DisplayContent mDisplayContent;
|
||
|
||
SurfaceControl mSurfaceControl;
|
||
|
||
// 窗口属性
|
||
|
||
int mLayer; // 层级
|
||
|
||
Rect mFrame; // 位置和大小
|
||
|
||
boolean mVisible; // 是否可见
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
### Q5: 窗口添加的完整流程是什么?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**窗口添加流程:**
|
||
|
||
|
||
|
||
```
|
||
|
||
1. Activity.attach()
|
||
|
||
└──> 创建PhoneWindow
|
||
|
||
2. Activity.onCreate()
|
||
|
||
└──> setContentView()
|
||
|
||
└──> PhoneWindow.setContentView()
|
||
|
||
└──> 创建DecorView
|
||
|
||
3. Activity.onResume()
|
||
|
||
└──> Activity.makeVisible()
|
||
|
||
└──> WindowManager.addView()
|
||
|
||
└──> WindowManagerGlobal.addView()
|
||
|
||
└──> 创建ViewRootImpl
|
||
|
||
└──> ViewRootImpl.setView()
|
||
|
||
└──> IWindowSession.addToDisplay()
|
||
|
||
└──> WMS.addWindow()
|
||
|
||
├──> 创建WindowState
|
||
|
||
├──> 创建Surface
|
||
|
||
└──> 更新布局
|
||
|
||
```
|
||
|
||
|
||
|
||
**关键代码:**
|
||
|
||
|
||
|
||
```java
|
||
|
||
// 1. Activity创建窗口
|
||
|
||
public final void attach(...) {
|
||
|
||
mWindow = new PhoneWindow(this, window, activityConfigCallback);
|
||
|
||
mWindow.setWindowManager(
|
||
|
||
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
|
||
|
||
mToken, mComponent.flattenToString(),
|
||
|
||
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
|
||
|
||
}
|
||
|
||
|
||
|
||
// 2. WMS添加窗口
|
||
|
||
public int addWindow(Session session, IWindow client, ...) {
|
||
|
||
// 权限检查
|
||
|
||
if (!checkCallingPermission(...)) {
|
||
|
||
return WindowManagerGlobal.ADD_PERMISSION_DENIED;
|
||
|
||
}
|
||
|
||
// 创建WindowState
|
||
|
||
WindowState win = new WindowState(this, session, client, ...);
|
||
|
||
// 添加到DisplayContent
|
||
|
||
DisplayContent displayContent = getDisplayContent(displayId);
|
||
|
||
displayContent.addWindow(win);
|
||
|
||
// 创建Surface
|
||
|
||
win.createSurfaceControl();
|
||
|
||
// 更新布局
|
||
|
||
performLayoutAndPlaceSurfacesLocked();
|
||
|
||
return WindowManagerGlobal.ADD_OKAY;
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
### Q6: WMS如何管理窗口的Z-Order(层级)?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**Z-Order管理机制:**
|
||
|
||
|
||
|
||
1. **基础层级**:由窗口类型决定(TYPE值)
|
||
|
||
2. **层级调整**:通过`WindowState.mLayer`动态计算
|
||
|
||
3. **层级排序**:DisplayContent维护窗口列表,按层级排序
|
||
|
||
|
||
|
||
**层级计算:**
|
||
|
||
|
||
|
||
```java
|
||
|
||
// WMS计算窗口层级
|
||
|
||
void assignWindowLayers(DisplayContent displayContent) {
|
||
|
||
int baseLayer = 0;
|
||
|
||
// 1. 系统窗口:最高层级
|
||
|
||
for (WindowState win : systemWindows) {
|
||
|
||
win.mLayer = baseLayer + win.mAttrs.type;
|
||
|
||
}
|
||
|
||
// 2. 应用窗口:中等层级
|
||
|
||
for (WindowState win : applicationWindows) {
|
||
|
||
win.mLayer = baseLayer + win.mAttrs.type;
|
||
|
||
}
|
||
|
||
// 3. 子窗口:最低层级(相对于父窗口)
|
||
|
||
for (WindowState win : childWindows) {
|
||
|
||
win.mLayer = win.mParentWindow.mLayer + win.mAttrs.type;
|
||
|
||
}
|
||
|
||
// 4. 按层级排序
|
||
|
||
displayContent.sortWindowsByLayer();
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
**影响层级的因素:**
|
||
|
||
|
||
|
||
- 窗口类型(TYPE)
|
||
|
||
- 窗口标志(FLAG)
|
||
|
||
- 窗口动画状态
|
||
|
||
- 窗口可见性
|
||
|
||
|
||
|
||
---
|
||
|
||
|
||
|
||
## 窗口管理类
|
||
|
||
|
||
|
||
### Q7: WindowState的作用是什么?它包含哪些关键信息?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**WindowState的作用:**
|
||
|
||
|
||
|
||
WindowState是WMS中表示一个窗口状态的核心类,包含了窗口的所有信息。
|
||
|
||
|
||
|
||
**关键信息:**
|
||
|
||
|
||
|
||
1. **窗口属性**:LayoutParams、类型、标志等
|
||
|
||
2. **窗口状态**:可见性、焦点状态、动画状态等
|
||
|
||
3. **窗口位置**:Frame、可见区域、裁剪区域等
|
||
|
||
4. **Surface信息**:SurfaceControl、Surface等
|
||
|
||
5. **窗口关系**:父窗口、子窗口、Token等
|
||
|
||
|
||
|
||
```java
|
||
|
||
class WindowState {
|
||
|
||
// 窗口属性
|
||
|
||
final WindowManager.LayoutParams mAttrs;
|
||
|
||
final WindowToken mToken;
|
||
|
||
final DisplayContent mDisplayContent;
|
||
|
||
// 窗口状态
|
||
|
||
boolean mVisible;
|
||
|
||
boolean mHasSurface;
|
||
|
||
boolean mIsAnimating;
|
||
|
||
// 窗口位置
|
||
|
||
Rect mFrame; // 窗口位置和大小
|
||
|
||
Rect mVisibleFrame; // 可见区域
|
||
|
||
Rect mContentFrame; // 内容区域
|
||
|
||
// Surface
|
||
|
||
SurfaceControl mSurfaceControl;
|
||
|
||
Surface mSurface;
|
||
|
||
// 窗口关系
|
||
|
||
WindowState mParentWindow;
|
||
|
||
ArrayList<WindowState> mChildWindows;
|
||
|
||
// 层级
|
||
|
||
int mLayer;
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
### Q8: DisplayContent的作用是什么?它如何管理窗口?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**DisplayContent的作用:**
|
||
|
||
|
||
|
||
DisplayContent表示一个显示设备上的所有窗口内容,管理该显示设备上的窗口栈、布局和显示。
|
||
|
||
|
||
|
||
**主要功能:**
|
||
|
||
|
||
|
||
1. **窗口管理**:维护该显示设备上的所有窗口
|
||
|
||
2. **窗口栈管理**:维护窗口的Z-Order顺序
|
||
|
||
3. **布局计算**:计算窗口的位置和大小
|
||
|
||
4. **显示配置**:管理显示设备的分辨率、方向等
|
||
|
||
|
||
|
||
```java
|
||
|
||
class DisplayContent {
|
||
|
||
final int mDisplayId;
|
||
|
||
final Display mDisplay;
|
||
|
||
// 窗口列表
|
||
|
||
final WindowList mWindows = new WindowList();
|
||
|
||
// 窗口栈
|
||
|
||
final ArrayList<TaskStack> mStacks = new ArrayList<>();
|
||
|
||
// 显示配置
|
||
|
||
Configuration mDisplayConfiguration;
|
||
|
||
// 添加窗口
|
||
|
||
void addWindow(WindowState win) {
|
||
|
||
mWindows.add(win);
|
||
|
||
assignWindowLayers();
|
||
|
||
}
|
||
|
||
// 布局计算
|
||
|
||
void performLayout() {
|
||
|
||
for (WindowState win : mWindows) {
|
||
|
||
computeWindowFrame(win);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
### Q9: WindowToken的作用是什么?为什么需要WindowToken?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**WindowToken的作用:**
|
||
|
||
|
||
|
||
WindowToken是窗口的令牌,用于:
|
||
|
||
1. **窗口分组**:将属于同一应用的窗口分组
|
||
|
||
2. **权限控制**:控制哪些窗口可以添加到Token
|
||
|
||
3. **窗口关联**:关联Activity、Service等组件
|
||
|
||
|
||
|
||
**为什么需要WindowToken:**
|
||
|
||
|
||
|
||
1. **安全性**:防止其他应用随意添加窗口到你的应用
|
||
|
||
2. **窗口管理**:统一管理同一组件的所有窗口
|
||
|
||
3. **生命周期**:Token销毁时,所有关联窗口都会被移除
|
||
|
||
|
||
|
||
```java
|
||
|
||
class WindowToken {
|
||
|
||
final IBinder token; // Token标识
|
||
|
||
final int windowType; // 窗口类型
|
||
|
||
final String name; // Token名称
|
||
|
||
// 关联的窗口列表
|
||
|
||
final ArrayList<WindowState> windows = new ArrayList<>();
|
||
|
||
// 添加窗口
|
||
|
||
void addWindow(WindowState win) {
|
||
|
||
windows.add(win);
|
||
|
||
}
|
||
|
||
// 移除窗口
|
||
|
||
void removeWindow(WindowState win) {
|
||
|
||
windows.remove(win);
|
||
|
||
if (windows.isEmpty()) {
|
||
|
||
// Token可以销毁
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
---
|
||
|
||
|
||
|
||
## 源码分析类
|
||
|
||
|
||
|
||
### Q10: WMS的addWindow方法做了哪些事情?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**addWindow方法流程:**
|
||
|
||
|
||
|
||
```java
|
||
|
||
public int addWindow(Session session, IWindow client, ...) {
|
||
|
||
// 1. 权限检查
|
||
|
||
if (!checkCallingPermission(...)) {
|
||
|
||
return WindowManagerGlobal.ADD_PERMISSION_DENIED;
|
||
|
||
}
|
||
|
||
// 2. 参数验证
|
||
|
||
if (attrs.type < FIRST_APPLICATION_WINDOW ||
|
||
|
||
attrs.type > LAST_APPLICATION_WINDOW) {
|
||
|
||
// 系统窗口需要特殊权限
|
||
|
||
}
|
||
|
||
// 3. 获取或创建WindowToken
|
||
|
||
WindowToken token = getWindowToken(attrs.token);
|
||
|
||
if (token == null) {
|
||
|
||
// 创建新Token
|
||
|
||
token = new WindowToken(...);
|
||
|
||
}
|
||
|
||
// 4. 创建WindowState
|
||
|
||
WindowState win = new WindowState(this, session, client, token, ...);
|
||
|
||
// 5. 添加到DisplayContent
|
||
|
||
DisplayContent displayContent = getDisplayContent(displayId);
|
||
|
||
displayContent.addWindow(win);
|
||
|
||
// 6. 创建Surface
|
||
|
||
win.createSurfaceControl();
|
||
|
||
// 7. 更新布局
|
||
|
||
performLayoutAndPlaceSurfacesLocked();
|
||
|
||
return WindowManagerGlobal.ADD_OKAY;
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
**关键步骤:**
|
||
|
||
|
||
|
||
1. **权限检查**:检查是否有权限添加该类型窗口
|
||
|
||
2. **Token管理**:获取或创建WindowToken
|
||
|
||
3. **创建WindowState**:创建窗口状态对象
|
||
|
||
4. **添加到DisplayContent**:将窗口添加到对应的显示设备
|
||
|
||
5. **创建Surface**:创建窗口的Surface用于绘制
|
||
|
||
6. **更新布局**:重新计算所有窗口的布局
|
||
|
||
|
||
|
||
### Q11: performLayoutAndPlaceSurfacesLocked方法的作用是什么?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**方法作用:**
|
||
|
||
|
||
|
||
`performLayoutAndPlaceSurfacesLocked`是WMS的核心布局方法,负责:
|
||
|
||
1. 计算所有窗口的位置和大小
|
||
|
||
2. 分配窗口的层级
|
||
|
||
3. 更新Surface的位置和大小
|
||
|
||
4. 处理窗口动画
|
||
|
||
|
||
|
||
**执行流程:**
|
||
|
||
|
||
|
||
```java
|
||
|
||
void performLayoutAndPlaceSurfacesLocked() {
|
||
|
||
// 1. 遍历所有显示设备
|
||
|
||
for (DisplayContent displayContent : mDisplayContents) {
|
||
|
||
// 2. 计算显示配置
|
||
|
||
displayContent.computeScreenConfiguration();
|
||
|
||
// 3. 应用窗口策略
|
||
|
||
applyWindowPolicy(displayContent);
|
||
|
||
// 4. 计算窗口位置和大小
|
||
|
||
for (WindowState win : displayContent.mWindows) {
|
||
|
||
computeWindowFrame(win);
|
||
|
||
}
|
||
|
||
// 5. 分配窗口层级
|
||
|
||
assignWindowLayers(displayContent);
|
||
|
||
// 6. 更新Surface
|
||
|
||
for (WindowState win : displayContent.mWindows) {
|
||
|
||
if (win.mHasSurface) {
|
||
|
||
updateSurface(win);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
// 7. 处理窗口动画
|
||
|
||
displayContent.mAnimator.updateWindowsLocked();
|
||
|
||
}
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
### Q12: WMS如何与SurfaceFlinger交互?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**交互流程:**
|
||
|
||
|
||
|
||
```
|
||
|
||
WMS
|
||
|
||
├──> 创建SurfaceControl
|
||
|
||
├──> 设置Surface属性(位置、大小、层级)
|
||
|
||
└──> 通过SurfaceControl与SurfaceFlinger通信
|
||
|
||
└──> SurfaceFlinger合成Surface并显示
|
||
|
||
```
|
||
|
||
|
||
|
||
**关键代码:**
|
||
|
||
|
||
|
||
```java
|
||
|
||
// WMS创建Surface
|
||
|
||
class WindowState {
|
||
|
||
void createSurfaceControl() {
|
||
|
||
mSurfaceControl = new SurfaceControl.Builder()
|
||
|
||
.setName(mWindowTag)
|
||
|
||
.setBufferSize(mFrame.width(), mFrame.height())
|
||
|
||
.setFormat(PixelFormat.TRANSLUCENT)
|
||
|
||
.build();
|
||
|
||
mSurface = new Surface(mSurfaceControl);
|
||
|
||
}
|
||
|
||
void updateSurface() {
|
||
|
||
// 设置Surface位置和大小
|
||
|
||
mSurfaceControl.setPosition(mFrame.left, mFrame.top);
|
||
|
||
mSurfaceControl.setSize(mFrame.width(), mFrame.height());
|
||
|
||
// 设置Surface层级
|
||
|
||
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||
|
||
t.setLayer(mSurfaceControl, mLayer);
|
||
|
||
t.apply();
|
||
|
||
}
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
---
|
||
|
||
|
||
|
||
## 性能优化类
|
||
|
||
|
||
|
||
### Q13: 如何优化窗口的创建和显示性能?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**优化策略:**
|
||
|
||
|
||
|
||
1. **减少窗口数量**:避免创建过多窗口
|
||
|
||
2. **延迟创建**:非关键窗口延迟创建
|
||
|
||
3. **复用窗口**:复用已有的窗口
|
||
|
||
4. **优化布局**:减少布局层级和复杂度
|
||
|
||
5. **使用硬件加速**:启用硬件加速提升绘制性能
|
||
|
||
|
||
|
||
```java
|
||
|
||
// 1. 延迟创建窗口
|
||
|
||
Handler.postDelayed(() -> {
|
||
|
||
createWindow();
|
||
|
||
}, 100);
|
||
|
||
|
||
|
||
// 2. 复用窗口
|
||
|
||
if (mWindow == null) {
|
||
|
||
mWindow = createWindow();
|
||
|
||
} else {
|
||
|
||
updateWindow(mWindow);
|
||
|
||
}
|
||
|
||
|
||
|
||
// 3. 启用硬件加速
|
||
|
||
<activity android:hardwareAccelerated="true" />
|
||
|
||
```
|
||
|
||
|
||
|
||
### Q14: 窗口动画对性能有什么影响?如何优化?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**影响:**
|
||
|
||
|
||
|
||
1. **CPU占用**:动画计算消耗CPU
|
||
|
||
2. **GPU占用**:动画渲染消耗GPU
|
||
|
||
3. **帧率下降**:复杂动画可能导致掉帧
|
||
|
||
|
||
|
||
**优化方法:**
|
||
|
||
|
||
|
||
1. **简化动画**:使用简单的动画效果
|
||
|
||
2. **使用硬件加速**:利用GPU加速动画
|
||
|
||
3. **减少动画时长**:缩短动画时间
|
||
|
||
4. **避免同时多个动画**:减少并发动画数量
|
||
|
||
|
||
|
||
```java
|
||
|
||
// 使用硬件加速动画
|
||
|
||
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
|
||
|
||
animator.setDuration(300);
|
||
|
||
animator.setInterpolator(new AccelerateDecelerateInterpolator());
|
||
|
||
animator.start();
|
||
|
||
```
|
||
|
||
|
||
|
||
---
|
||
|
||
|
||
|
||
## 问题排查类
|
||
|
||
|
||
|
||
### Q15: 如何排查窗口显示异常的问题?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**排查步骤:**
|
||
|
||
|
||
|
||
1. **检查窗口状态**:使用`adb shell dumpsys window`
|
||
|
||
2. **检查Surface状态**:查看Surface是否创建成功
|
||
|
||
3. **检查布局**:查看窗口的Frame是否正确
|
||
|
||
4. **检查层级**:查看窗口的Layer是否正确
|
||
|
||
5. **使用Systrace**:分析窗口创建和布局流程
|
||
|
||
|
||
|
||
```bash
|
||
|
||
# 1. 查看窗口信息
|
||
|
||
adb shell dumpsys window windows
|
||
|
||
|
||
|
||
# 2. 查看窗口层级
|
||
|
||
adb shell dumpsys window displays
|
||
|
||
|
||
|
||
# 3. 使用Systrace分析
|
||
|
||
python systrace.py -t 10 -o trace.html wm
|
||
|
||
```
|
||
|
||
|
||
|
||
### Q16: 窗口泄漏如何排查和解决?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**排查方法:**
|
||
|
||
|
||
|
||
1. **检查WindowManager引用**:确保及时移除窗口
|
||
|
||
2. **检查生命周期**:确保在onDestroy中移除窗口
|
||
|
||
3. **使用LeakCanary**:检测窗口泄漏
|
||
|
||
4. **检查WindowToken**:确保Token正确管理
|
||
|
||
|
||
|
||
```java
|
||
|
||
// 正确的窗口管理
|
||
|
||
class MyActivity extends Activity {
|
||
|
||
private View floatingView;
|
||
|
||
@Override
|
||
|
||
protected void onCreate(Bundle savedInstanceState) {
|
||
|
||
super.onCreate(savedInstanceState);
|
||
|
||
// 创建悬浮窗
|
||
|
||
createFloatingWindow();
|
||
|
||
}
|
||
|
||
@Override
|
||
|
||
protected void onDestroy() {
|
||
|
||
super.onDestroy();
|
||
|
||
// 必须移除窗口
|
||
|
||
if (floatingView != null) {
|
||
|
||
WindowManager wm = getWindowManager();
|
||
|
||
wm.removeView(floatingView);
|
||
|
||
floatingView = null;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
---
|
||
|
||
|
||
|
||
## 多窗口相关
|
||
|
||
|
||
|
||
### Q17: 分屏模式是如何实现的?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**分屏实现原理:**
|
||
|
||
|
||
|
||
1. **任务栈管理**:每个分屏窗口对应一个TaskStack
|
||
|
||
2. **窗口布局**:WMS计算每个窗口的位置和大小
|
||
|
||
3. **输入事件分发**:根据触摸位置分发到对应窗口
|
||
|
||
4. **焦点管理**:管理两个窗口的焦点切换
|
||
|
||
|
||
|
||
```java
|
||
|
||
// 分屏窗口布局
|
||
|
||
void layoutSplitScreenWindows(DisplayContent displayContent) {
|
||
|
||
// 计算分屏窗口大小
|
||
|
||
Rect primaryFrame = new Rect(0, 0, screenWidth / 2, screenHeight);
|
||
|
||
Rect secondaryFrame = new Rect(screenWidth / 2, 0, screenWidth, screenHeight);
|
||
|
||
// 设置主窗口位置
|
||
|
||
primaryWindow.mFrame = primaryFrame;
|
||
|
||
// 设置次窗口位置
|
||
|
||
secondaryWindow.mFrame = secondaryFrame;
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
### Q18: 悬浮窗(Overlay Window)如何实现?
|
||
|
||
|
||
|
||
**答案:**
|
||
|
||
|
||
|
||
**实现步骤:**
|
||
|
||
|
||
|
||
1. **申请权限**:`SYSTEM_ALERT_WINDOW`权限
|
||
|
||
2. **设置窗口类型**:`TYPE_APPLICATION_OVERLAY`
|
||
|
||
3. **创建窗口**:使用WindowManager添加窗口
|
||
|
||
4. **管理生命周期**:及时移除窗口
|
||
|
||
|
||
|
||
```java
|
||
|
||
// 创建悬浮窗
|
||
|
||
private void createOverlayWindow() {
|
||
|
||
// 1. 检查权限
|
||
|
||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||
|
||
if (!Settings.canDrawOverlays(this)) {
|
||
|
||
// 请求权限
|
||
|
||
requestOverlayPermission();
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
// 2. 创建窗口参数
|
||
|
||
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
||
|
||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||
|
||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||
|
||
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
|
||
|
||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
|
||
|
||
PixelFormat.TRANSLUCENT
|
||
|
||
);
|
||
|
||
// 3. 创建视图
|
||
|
||
View overlayView = LayoutInflater.from(this)
|
||
|
||
.inflate(R.layout.overlay_window, null);
|
||
|
||
// 4. 添加窗口
|
||
|
||
WindowManager wm = getSystemService(Context.WINDOW_SERVICE);
|
||
|
||
wm.addView(overlayView, params);
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
---
|
||
|
||
|
||
|
||
## 总结
|
||
|
||
|
||
|
||
WMS窗口面试题主要涵盖:
|
||
|
||
|
||
|
||
1. **基础概念**:WMS作用、窗口类型、层级关系
|
||
|
||
2. **架构原理**:WMS架构、窗口添加流程、Z-Order管理
|
||
|
||
3. **窗口管理**:WindowState、D |