33 KiB
技术面试问题回答
一、Framework开发经验相关
Q1: 请介绍一下你的Framework开发经验,主要涉及哪些方面?
A: 我拥有4年Framework深度开发经验,主要专注于Android系统框架与中间件开发。具体包括:
- 系统核心服务:深入理解AMS、PKMS、PMS、Input、DPM等核心服务的运行机制和实现原理
- 窗口系统:精通WMS、WMShell、View系统,熟悉多窗口场景(分屏、浮窗、自由窗等)的绘制原理
- Binder通信:深入理解Binder机制,熟悉系统服务间通信原理
- 系统功能:熟悉权限管理、通知系统、系统升级、分屏、多屏协同等功能的实现机制
- 企业级中间件:参与过2个企业级中间件框架的开发与维护,具备框架设计与架构能力
Q2: 能详细说说Android系统启动流程吗?
A: Android系统启动流程主要包括以下几个阶段:
- Bootloader阶段:加载Linux内核
- Kernel启动:初始化硬件驱动,启动init进程
- Init进程:解析init.rc,启动Zygote进程和ServiceManager
- Zygote进程:预加载类和资源,fork出SystemServer进程
- SystemServer:启动各类系统服务(AMS、WMS、PKMS等)
- Launcher启动:系统服务就绪后启动Launcher,用户可见
在整个过程中,我重点关注AMS、WMS等核心服务的启动顺序和依赖关系,以及它们如何协同工作。
Q3: 你提到熟悉Binder机制,能说说Binder的工作原理吗?
A: Binder是Android的进程间通信机制,主要特点:
- 一次拷贝:通过mmap实现,数据只需拷贝一次,效率高
- 安全性:基于内核驱动,有完善的权限验证机制
- 架构:采用C/S架构,包含Client、Server、ServiceManager、Binder驱动四部分
工作流程:
- Server向ServiceManager注册服务
- Client通过ServiceManager获取服务代理
- Client调用代理方法,通过Binder驱动传递到Server
- Server处理请求并返回结果
在实际开发中,我经常需要自定义Binder服务,理解AIDL的生成机制,以及如何优化Binder调用的性能。
二、系统稳定性与问题定位
Q4: 如何定位和解决ANR问题?
A: ANR定位我通常采用以下步骤:
- 日志分析:查看
/data/anr/traces.txt,定位主线程阻塞位置 - 工具分析:使用Systrace、Perfetto分析主线程执行时间线
- 常见原因:
- 主线程执行耗时操作(网络、数据库、文件IO)
- 死锁或锁竞争
- 系统服务响应慢(如AMS、WMS)
解决方案:
- 耗时操作移到子线程(线程池、协程)
- 优化数据库查询,使用索引
- 避免主线程持有锁时间过长
- 对于系统服务问题,需要分析Framework层代码
Q5: 如何排查内存泄漏问题?
A: 内存泄漏排查流程:
- 工具检测:使用LeakCanary、MAT(Memory Analyzer Tool)进行检测
- 分析堆转储:查看对象引用链,找出泄漏路径
- 常见场景:
- 静态变量持有Context/Activity引用
- 监听器未解注册(BroadcastReceiver、EventBus等)
- 内部类持有外部类引用(Handler、Thread等)
- 单例模式持有Context
预防措施:
- 使用WeakReference持有Context
- 及时解注册监听器
- Handler使用静态内部类+WeakReference
- 定期进行内存分析
Q6: 遇到过冻屏、死机问题吗?如何定位?
A: 遇到过,这类问题通常比较复杂,我的定位思路:
- 日志收集:抓取logcat、kernel log、tombstone等
- 分析关键信息:
- 冻屏:检查主线程是否阻塞,是否有死锁
- 死机:查看kernel panic信息,分析硬件/驱动问题
- 使用工具:
- Systrace分析CPU调度
- Perfetto分析系统整体状态
- 使用
adb shell dumpsys分析各服务状态
实际案例:曾遇到一个冻屏问题,通过Systrace发现是WMS在窗口切换时发生死锁,最终通过优化锁的粒度解决。
三、性能优化经验
Q7: 你在性能优化方面有哪些经验?
A: 性能优化我主要从以下几个方面入手:
系统级优化:
- CPU调度:了解系统调度机制,优化线程优先级和CPU亲和性
- 内存优化:减少内存分配,使用对象池,优化数据结构
- I/O优化:使用异步IO,批量操作,减少文件读写次数
应用层优化:
- 启动优化:减少Application初始化时间,延迟加载非关键组件
- 布局优化:减少布局层级,使用ConstraintLayout,避免过度绘制
- 网络优化:请求合并,使用缓存,压缩数据
工具使用:
- 使用Perfetto、Systrace分析性能瓶颈
- 使用Profiler监控CPU、内存、网络使用情况
- 使用StrictMode检测主线程耗时操作
Q8: 如何优化应用启动速度?
A: 启动优化策略:
-
Application优化:
- 延迟初始化非关键组件(使用懒加载)
- 将初始化任务放到子线程或异步执行
- 使用启动器模式,控制初始化顺序
-
首屏优化:
- 减少首屏布局复杂度
- 使用ViewStub延迟加载
- 预加载关键数据
-
技术手段:
- 使用App Startup库统一管理初始化
- 使用Trace API标记启动流程
- 分析启动时间线,找出瓶颈
实际效果:在某个项目中,通过优化将启动时间从3.5秒降低到1.8秒。
四、架构设计与项目经验
Q9: 你在架构设计方面有哪些经验?
A: 架构设计经验:
应用层架构:
- 熟练掌握MVC、MVP、MVVM架构模式,根据项目特点选择合适架构
- 组件化开发:将业务模块解耦,实现模块独立开发和测试
- 接口设计:定义清晰的模块间接口,降低耦合度
Framework层架构:
- 参与过2个企业级中间件框架的开发,负责核心模块设计
- 熟悉系统服务架构,理解服务注册、发现、调用机制
- 模块解耦:通过接口抽象、依赖注入等方式实现模块解耦
设计原则:
- 单一职责原则
- 开闭原则
- 依赖倒置原则
- 关注点分离
Q10: 能介绍一下你参与的大型项目吗?
A: 我参与过多个大型项目,主要包括:
Framework层项目:
- 企业级中间件框架:负责核心服务模块的设计与开发,支持多业务线接入
- 系统定制化项目:参与系统服务的定制化开发,优化系统性能和稳定性
应用层项目:
- 电商App:负责核心购物流程、支付模块开发,处理高并发场景
- 社交即时通讯App:负责消息推送、音视频通话等核心功能
- 工具类App:涉及多个垂直领域的工具应用
在这些项目中,我主要负责:
- 架构设计与技术选型
- 核心模块开发与性能优化
- 复杂问题排查与解决
- 代码review和技术分享
五、复杂问题解决能力
Q11: 能分享一个你解决过的复杂技术问题吗?
A: 案例:多窗口场景下的内存泄漏问题
问题描述:
在分屏场景下,应用退出后内存持续增长,最终导致OOM。
排查过程:
- 使用MAT分析堆转储,发现大量Window对象未释放
- 通过Systrace分析,发现WMS在窗口销毁时未正确清理
- 深入Framework代码,发现是窗口状态机在特定场景下未正确转换
解决方案:
- 在应用层:确保Activity正确调用onDestroy,及时释放资源
- 在Framework层:修复窗口状态机的状态转换逻辑,确保窗口正确销毁
- 添加监控:增加窗口泄漏检测机制,及时发现问题
结果: 问题彻底解决,内存使用恢复正常,并建立了预防机制。
Q12: 如何快速定位和解决线上Crash问题?
A: Crash问题处理流程:
-
信息收集:
- 收集Crash堆栈、设备信息、系统版本
- 查看用户操作路径,复现问题
-
问题分析:
- 分析堆栈信息,定位崩溃位置
- 检查是否为空指针、数组越界、类型转换等常见问题
- 查看相关代码变更历史
-
解决方案:
- 添加空值检查、边界检查
- 使用try-catch捕获异常
- 对于Framework层问题,需要深入分析系统服务
-
预防措施:
- 完善单元测试和集成测试
- 使用Crash监控平台(如Firebase Crashlytics)
- 代码review时重点关注异常处理
六、技术深度与学习能力
Q13: 你是如何保持技术更新的?
A: 技术学习方式:
-
源码阅读:
- 定期阅读Android Framework源码,理解系统实现原理
- 关注Google官方文档和AOSP更新
-
技术社区:
- 关注技术博客、GitHub优秀项目
- 参与技术会议和分享
-
实践总结:
- 在项目中实践新技术
- 总结问题解决经验,形成知识沉淀
-
工具使用:
- 学习使用新的调试工具(如Perfetto)
- 关注性能分析工具的发展
Q14: 对于Android新版本特性,你是如何学习和应用的?
A: 学习新版本特性的方法:
-
官方文档:
- 第一时间阅读Google官方发布说明
- 关注新API和废弃API的变化
-
实践验证:
- 在测试项目中验证新特性
- 分析新特性的实现原理
-
兼容性处理:
- 考虑向后兼容性
- 使用版本适配库(如AndroidX)
-
团队分享:
- 将新特性应用到实际项目
- 在团队内部分享学习心得
七、团队协作与项目管理
Q15: 在团队协作中,你是如何保证代码质量的?
A: 代码质量保障措施:
-
代码规范:
- 遵循团队代码规范
- 使用代码检查工具(Lint、Checkstyle)
-
Code Review:
- 认真review他人代码,提出改进建议
- 接受他人review,持续改进
-
测试:
- 编写单元测试和集成测试
- 进行充分的自测
-
文档:
- 编写清晰的代码注释
- 维护技术文档
Q16: 你如何平衡开发效率和代码质量?
A: 平衡策略:
-
技术选型:
- 选择成熟稳定的技术方案,避免过度设计
- 使用合适的框架和工具,提高开发效率
-
代码复用:
- 抽取公共组件,避免重复开发
- 建立组件库,提高复用率
-
迭代优化:
- 先实现功能,再逐步优化
- 定期重构,保持代码质量
-
工具辅助:
- 使用IDE插件提高编码效率
- 使用CI/CD自动化测试和部署
总结
以上是我基于10年Android开发经验,在Framework层和应用层开发、系统稳定性保障、性能优化、架构设计等方面的技术积累。我具备解决复杂技术问题的能力,能够从系统层面思考问题,提供最优解决方案。同时,我注重团队协作,能够将技术经验分享给团队,共同提升技术水平。
WMS窗口常见面试题
本文档整理了Android WMS(Window Manager Service)窗口管理相关的常见面试题,涵盖基础概念、架构原理、源码分析、问题排查等多个方面。
目录
基础概念类
Q1: 什么是WMS?它的主要职责是什么?
答案:
WMS(Window Manager Service)是Android窗口系统的核心服务,运行在system_server进程中。
主要职责:
-
窗口管理:管理所有窗口的创建、显示、销毁等生命周期
-
窗口层级管理:维护窗口的Z-Order顺序,决定窗口的显示优先级
-
布局计算:计算窗口的位置、大小和可见区域
-
输入事件分发:将触摸、按键等输入事件分发给正确的窗口
-
窗口动画:管理窗口的显示、隐藏、切换等动画效果
-
屏幕旋转:处理屏幕方向变化时的窗口布局调整
-
多显示支持:支持多个显示设备的窗口管理
// WMS是系统服务,在SystemServer中启动
public class SystemServer {
private void startOtherServices(...) {
WindowManagerService wm = WindowManagerService.main(...);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
}
}
Q2: WMS与WindowManager、WindowManagerGlobal的关系是什么?
答案:
这三者的关系如下:
-
WindowManager:应用层接口,开发者使用的API
-
WindowManagerGlobal:应用层实现,管理ViewRootImpl和窗口会话
-
WindowManagerService:系统服务,实际管理窗口的服务端
调用流程:
应用层:WindowManager.addView()
↓
WindowManagerGlobal.addView()
↓
ViewRootImpl.setView()
↓
IWindowSession.addToDisplay() (Binder调用)
↓
WMS.addWindow() (服务端)
// 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: 窗口类型有哪些?它们的层级关系是什么?
答案:
窗口类型:
- 应用窗口(APPLICATION)
- TYPE_APPLICATION:普通Activity窗口
- TYPE_APPLICATION_STARTING:启动窗口
- TYPE_BASE_APPLICATION:应用基础窗口
- 子窗口(SUB_WINDOW)
- TYPE_APPLICATION_PANEL:应用面板
- TYPE_APPLICATION_SUB_PANEL:应用子面板
- TYPE_APPLICATION_ATTACHED_DIALOG:附加对话框
- 系统窗口(SYSTEM_WINDOW)
- TYPE_STATUS_BAR:状态栏
- TYPE_NAVIGATION_BAR:导航栏
- TYPE_SYSTEM_ALERT:系统警告窗口
- TYPE_TOAST:Toast窗口
- TYPE_APPLICATION_OVERLAY:悬浮窗(需要权限)
层级关系(Z-Order):
系统窗口(最高)
↓
应用窗口(中等)
↓
子窗口(最低)
// 窗口类型定义
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 │
└─────────────────────────────────┘
核心组件:
-
WindowManagerService:WMS主类,管理所有窗口
-
WindowState:窗口状态,表示一个窗口的所有信息
-
DisplayContent:显示内容,管理一个显示设备上的所有窗口
-
WindowToken:窗口令牌,用于窗口分组和权限控制
-
WindowAnimator:窗口动画控制器
-
WindowStateAnimator:单个窗口的动画状态
// 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
└──> 更新布局
关键代码:
// 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管理机制:
-
基础层级:由窗口类型决定(TYPE值)
-
层级调整:通过
WindowState.mLayer动态计算 -
层级排序:DisplayContent维护窗口列表,按层级排序
层级计算:
// 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中表示一个窗口状态的核心类,包含了窗口的所有信息。
关键信息:
-
窗口属性:LayoutParams、类型、标志等
-
窗口状态:可见性、焦点状态、动画状态等
-
窗口位置:Frame、可见区域、裁剪区域等
-
Surface信息:SurfaceControl、Surface等
-
窗口关系:父窗口、子窗口、Token等
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表示一个显示设备上的所有窗口内容,管理该显示设备上的窗口栈、布局和显示。
主要功能:
-
窗口管理:维护该显示设备上的所有窗口
-
窗口栈管理:维护窗口的Z-Order顺序
-
布局计算:计算窗口的位置和大小
-
显示配置:管理显示设备的分辨率、方向等
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是窗口的令牌,用于:
-
窗口分组:将属于同一应用的窗口分组
-
权限控制:控制哪些窗口可以添加到Token
-
窗口关联:关联Activity、Service等组件
为什么需要WindowToken:
-
安全性:防止其他应用随意添加窗口到你的应用
-
窗口管理:统一管理同一组件的所有窗口
-
生命周期:Token销毁时,所有关联窗口都会被移除
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方法流程:
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;
}
关键步骤:
-
权限检查:检查是否有权限添加该类型窗口
-
Token管理:获取或创建WindowToken
-
创建WindowState:创建窗口状态对象
-
添加到DisplayContent:将窗口添加到对应的显示设备
-
创建Surface:创建窗口的Surface用于绘制
-
更新布局:重新计算所有窗口的布局
Q11: performLayoutAndPlaceSurfacesLocked方法的作用是什么?
答案:
方法作用:
performLayoutAndPlaceSurfacesLocked是WMS的核心布局方法,负责:
-
计算所有窗口的位置和大小
-
分配窗口的层级
-
更新Surface的位置和大小
-
处理窗口动画
执行流程:
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并显示
关键代码:
// 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. 延迟创建窗口
Handler.postDelayed(() -> {
createWindow();
}, 100);
// 2. 复用窗口
if (mWindow == null) {
mWindow = createWindow();
} else {
updateWindow(mWindow);
}
// 3. 启用硬件加速
<activity android:hardwareAccelerated="true" />
Q14: 窗口动画对性能有什么影响?如何优化?
答案:
影响:
-
CPU占用:动画计算消耗CPU
-
GPU占用:动画渲染消耗GPU
-
帧率下降:复杂动画可能导致掉帧
优化方法:
-
简化动画:使用简单的动画效果
-
使用硬件加速:利用GPU加速动画
-
减少动画时长:缩短动画时间
-
避免同时多个动画:减少并发动画数量
// 使用硬件加速动画
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
animator.setDuration(300);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.start();
问题排查类
Q15: 如何排查窗口显示异常的问题?
答案:
排查步骤:
-
检查窗口状态:使用
adb shell dumpsys window -
检查Surface状态:查看Surface是否创建成功
-
检查布局:查看窗口的Frame是否正确
-
检查层级:查看窗口的Layer是否正确
-
使用Systrace:分析窗口创建和布局流程
# 1. 查看窗口信息
adb shell dumpsys window windows
# 2. 查看窗口层级
adb shell dumpsys window displays
# 3. 使用Systrace分析
python systrace.py -t 10 -o trace.html wm
Q16: 窗口泄漏如何排查和解决?
答案:
排查方法:
-
检查WindowManager引用:确保及时移除窗口
-
检查生命周期:确保在onDestroy中移除窗口
-
使用LeakCanary:检测窗口泄漏
-
检查WindowToken:确保Token正确管理
// 正确的窗口管理
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: 分屏模式是如何实现的?
答案:
分屏实现原理:
-
任务栈管理:每个分屏窗口对应一个TaskStack
-
窗口布局:WMS计算每个窗口的位置和大小
-
输入事件分发:根据触摸位置分发到对应窗口
-
焦点管理:管理两个窗口的焦点切换
// 分屏窗口布局
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)如何实现?
答案:
实现步骤:
-
申请权限:
SYSTEM_ALERT_WINDOW权限 -
设置窗口类型:
TYPE_APPLICATION_OVERLAY -
创建窗口:使用WindowManager添加窗口
-
管理生命周期:及时移除窗口
// 创建悬浮窗
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窗口面试题主要涵盖:
-
基础概念:WMS作用、窗口类型、层级关系
-
架构原理:WMS架构、窗口添加流程、Z-Order管理
-
窗口管理:WindowState、D