【Android面试】窗口机制专题

文章目录

  • 一、基础概念与体系架构
    • [1. 简述 Window、WindowManager、WMS 三者关系与职责](#1. 简述 Window、WindowManager、WMS 三者关系与职责)
    • [2. Android 中有哪些 Window 类型?应用与系统窗口区别](#2. Android 中有哪些 Window 类型?应用与系统窗口区别)
    • [3. addView/updateViewLayout/removeView 流程](#3. addView/updateViewLayout/removeView 流程)
    • [4. 为什么 DecorView 是 Window 根 View?与 Window 如何绑定](#4. 为什么 DecorView 是 Window 根 View?与 Window 如何绑定)
    • [5. PhoneWindow 作用](#5. PhoneWindow 作用)
  • [二、WindowManager 与 View 关联核心](#二、WindowManager 与 View 关联核心)
    • [1. 同一个 WM 可添加多个 View?不同 WM 实例区别](#1. 同一个 WM 可添加多个 View?不同 WM 实例区别)
    • [2. addView 中 LayoutInflater 与 WM 流程](#2. addView 中 LayoutInflater 与 WM 流程)
    • [3. ViewRootImpl 核心作用 & 与 WMS 通信方式](#3. ViewRootImpl 核心作用 & 与 WMS 通信方式)
    • [4. 子线程不能更新 UI 原因 & 与 ViewRootImpl 关系](#4. 子线程不能更新 UI 原因 & 与 ViewRootImpl 关系)
    • [5. LayoutParams 哪些参数影响窗口展示](#5. LayoutParams 哪些参数影响窗口展示)
  • [三、WMS 核心原理(大厂深度必问)](#三、WMS 核心原理(大厂深度必问))
    • [1. WMS 如何管理窗口?Z-Order 如何计算](#1. WMS 如何管理窗口?Z-Order 如何计算)
    • [2. App 与 WMS 通信方式 & Binder 作用](#2. App 与 WMS 通信方式 & Binder 作用)
    • [3. WindowToken 作用?为什么 Activity/Dialog 要不同 Token](#3. WindowToken 作用?为什么 Activity/Dialog 要不同 Token)
    • [4. AppToken 与 WindowToken 区别](#4. AppToken 与 WindowToken 区别)
    • [5. WMS 感知窗口生命周期?Activity 与窗口生命周期对应](#5. WMS 感知窗口生命周期?Activity 与窗口生命周期对应)
    • [6. 如何判断窗口可获取焦点?焦点切换逻辑](#6. 如何判断窗口可获取焦点?焦点切换逻辑)
  • [四、Activity/Dialog/Toast 窗口原理](#四、Activity/Dialog/Toast 窗口原理)
    • [1. Activity 窗口在哪个生命周期创建 & 添加](#1. Activity 窗口在哪个生命周期创建 & 添加)
    • [2. Dialog 与 Activity 窗口区别?非 Activity 上下文报错原因](#2. Dialog 与 Activity 窗口区别?非 Activity 上下文报错原因)
    • [3. Toast 窗口类型 & 限制 & 崩溃原因](#3. Toast 窗口类型 & 限制 & 崩溃原因)
    • [4. 悬浮窗权限校验逻辑](#4. 悬浮窗权限校验逻辑)
    • [5. Dialog 依赖 Activity Window?脱离 Activity 展示要解决什么](#5. Dialog 依赖 Activity Window?脱离 Activity 展示要解决什么)
  • [五、Surface 与窗口渲染](#五、Surface 与窗口渲染)
    • [1. Window 与 Surface 关系 & 窗口渲染流程](#1. Window 与 Surface 关系 & 窗口渲染流程)
    • [2. SurfaceFlinger 作用 & 与 WMS、App 协作](#2. SurfaceFlinger 作用 & 与 WMS、App 协作)
    • [3. 硬件加速 & 开启后渲染变化](#3. 硬件加速 & 开启后渲染变化)
    • [4. SurfaceView、TextureView 与普通 View 区别](#4. SurfaceView、TextureView 与普通 View 区别)
    • [5. invalidate/requestLayout 如何到 WMS & SF](#5. invalidate/requestLayout 如何到 WMS & SF)
  • [六、Token 机制与权限校验(字节 / 阿里高频)](#六、Token 机制与权限校验(字节 / 阿里高频))
    • [1. 为什么用 WindowToken 校验窗口合法性](#1. 为什么用 WindowToken 校验窗口合法性)
    • [2. 应用后台弹窗口被拦截核心逻辑](#2. 应用后台弹窗口被拦截核心逻辑)
    • [3. 不同版本对 Token、后台弹窗的改动](#3. 不同版本对 Token、后台弹窗的改动)
    • [4. Application 上下文创建 Dialog 崩溃原因](#4. Application 上下文创建 Dialog 崩溃原因)
    • [5. 如何绕过 Token 实现后台弹窗?系统如何修复](#5. 如何绕过 Token 实现后台弹窗?系统如何修复)
  • 七、多窗口、分屏、折叠屏
    • [1. 多窗口下 WMS 如何管理应用窗口](#1. 多窗口下 WMS 如何管理应用窗口)
    • [2. 分屏下窗口尺寸、生命周期、焦点变化](#2. 分屏下窗口尺寸、生命周期、焦点变化)
    • [3. 折叠屏切换时窗口重建与布局](#3. 折叠屏切换时窗口重建与布局)
    • [4. 多窗口与 Activity 启动模式关系](#4. 多窗口与 Activity 启动模式关系)
  • 八、异常场景与问题排查
    • [1. WindowLeaked 场景 & 如何避免](#1. WindowLeaked 场景 & 如何避免)
    • [2. 后台切回黑屏 / 白屏与窗口机制关系](#2. 后台切回黑屏 / 白屏与窗口机制关系)
    • [3. 窗口动画卡顿、黑屏分析角度](#3. 窗口动画卡顿、黑屏分析角度)
    • [4. 软键盘弹出挤压布局原理](#4. 软键盘弹出挤压布局原理)
  • 九、大厂开放性问题(简要答案)
    • [1. 窗口从创建到显示全流程](#1. 窗口从创建到显示全流程)
    • [2. 全局悬浮窗实现要点](#2. 全局悬浮窗实现要点)
    • [3. 系统窗口与应用窗口通信](#3. 系统窗口与应用窗口通信)
    • [4. 优化 Activity 窗口启动速度](#4. 优化 Activity 窗口启动速度)
    • [5. Android 12+ 窗口核心改动](#5. Android 12+ 窗口核心改动)

一、基础概念与体系架构

1. 简述 Window、WindowManager、WMS 三者关系与职责

答案:

Window:抽象类,代表一个窗口,是 View 的容器。具体实现是 PhoneWindow。

WindowManager:应用层接口,继承自 ViewManager,负责 添加、更新、删除窗口,是 App 与 WMS 交互的入口。

WMS(WindowManagerService):系统服务,运行在 system_server,负责所有窗口的管理、层级、尺寸、焦点、动画、显示排序。

关系:App 通过 WindowManager 跨进程通信(Binder)请求 WMS,WMS 真正决策窗口怎么显示。

2. Android 中有哪些 Window 类型?应用与系统窗口区别

答案:窗口类型分三大类:

应用窗口:TYPE_BASE_APPLICATION、TYPE_APPLICATION(Activity 默认)

子窗口:TYPE_APPLICATION_PANEL(Dialog、PopupWindow),必须依附于主窗口

系统窗口:TYPE_STATUS_BAR、TYPE_TOAST、TYPE_SYSTEM_ALERT 等

区别:

应用窗口:需要 Activity/Token 才能创建,受生命周期管理。

系统窗口:需要额外权限,不受单个 Activity 生命周期控制。

3. addView/updateViewLayout/removeView 流程

  • addView
    创建 ViewRootImpl
    建立与 WMS 的连接
    向 WMS 注册窗口,申请 Surface
    开始首次 measure/layout/draw
  • updateViewLayout
    更新 LayoutParams
    请求 WMS 重新布局窗口
    触发 requestLayout
  • removeView
    销毁 Surface
    向 WMS 注销窗口
    解除 ViewRoot 与 View 的关联
    处理窗口泄漏检查

4. 为什么 DecorView 是 Window 根 View?与 Window 如何绑定

答案:

DecorView 是 Activity/Window 界面的 最顶层 View,包含标题栏 + 内容布局。

它是 Window 唯一直接持有的 View。

绑定:

Activity 启动时,PhoneWindow 会创建 DecorView,并通过 setContentView 将布局添加到 DecorView 的 content 容器中。

5. PhoneWindow 作用

答案:

Window 的唯一系统实现类。

内部管理 DecorView、标题栏、背景、事件分发、输入法等。

是 Activity 和 WindowManager 之间的桥梁。

二、WindowManager 与 View 关联核心

1. 同一个 WM 可添加多个 View?不同 WM 实例区别

答案:

同一个 WindowManager 可以添加多个 View,每个 View 对应一个窗口。

每个 WindowManager 实例绑定一个 Context(Activity/Application)。

Activity 的 WM 会携带 Activity Token,Application 没有,所以不能直接弹 Dialog。

2. addView 中 LayoutInflater 与 WM 流程

答案:

LayoutInflater 把 xml 解析成 View 树

调用 WindowManager.addView(view, params)

内部创建 ViewRootImpl

ViewRootImpl 负责与 WMS 通信、创建 Surface、触发绘制

3. ViewRootImpl 核心作用 & 与 WMS 通信方式

答案:核心作用:

每个窗口对应一个 ViewRootImpl

管理 measure、layout、draw

管理 输入事件分发

管理 Surface 与渲染

管理 与 WMS 的通信
ViewRootImpl 是在 DecorView 被添加到 WindowManager 时创建的;实际创建时机在 Activity 的 onResume() 之后

通信:通过 Binder 接口 IWindowSession 与 WMS 通信。

4. 子线程不能更新 UI 原因 & 与 ViewRootImpl 关系

答案:

ViewRootImpl 里有 mThread 检查,记录创建时的线程(主线程)。

requestLayout/invalidate 最终会走到 checkThread()。

子线程更新会抛出 CalledFromWrongThreadException。

本质: UI 操作非线程安全,系统用单线程检查强制约束。

5. LayoutParams 哪些参数影响窗口展示

答案:

type:窗口类型(决定层级、权限)

width/height:宽高

gravity:对齐方式

flags:FLAG_NOT_FOCUSABLE、FLAG_NOT_TOUCHABLE 等

format:像素格式

dimAmount:背景灰度

token:窗口令牌(权限校验)

三、WMS 核心原理(大厂深度必问)

1. WMS 如何管理窗口?Z-Order 如何计算

答案:

WMS 内部用 WindowState 描述每个窗口。

按 type + 层级规则 排序 Z 序。

层级:系统窗口 > 子窗口 > 应用窗口。

同类型按添加顺序、焦点、显示状态调整。

2. App 与 WMS 通信方式 & Binder 作用

答案:

通信通道:IWindowSession(每个进程一个)

窗口回调:IWindow(每个窗口一个)

Binder 作用:跨进程传递 窗口操作、尺寸、事件、生命周期。

3. WindowToken 作用?为什么 Activity/Dialog 要不同 Token

答案:

WindowToken 是窗口的身份令牌,用于权限校验。

防止恶意应用随意弹系统级窗口。

Activity 窗口使用 AppToken/ActivityRecord Token。

Dialog 作为子窗口,必须使用 宿主 Activity 的 Token。

4. AppToken 与 WindowToken 区别

答案:

AppToken:对应一个 Activity,生命周期与 Activity 绑定。

WindowToken:对应一组窗口,用于校验窗口合法性。

Activity 窗口用 AppToken,普通子窗口用 WindowToken。

5. WMS 感知窗口生命周期?Activity 与窗口生命周期对应

答案:

Activity 生命周期通过 AMS 通知 WMS。

对应关系:

onCreate:创建窗口

onResume:窗口真正 addView、显示

onPause:失去焦点

onDestroy:移除窗口

6. 如何判断窗口可获取焦点?焦点切换逻辑

答案:

焦点条件:

LayoutParams.FLAG_NOT_FOCUSABLE 为 false

窗口可见、不被完全遮挡

属于当前前台应用

切换:

触摸 / 按键 → WMS 计算顶层可焦点窗口 → 通知对应窗口获取焦点。

四、Activity/Dialog/Toast 窗口原理

1. Activity 窗口在哪个生命周期创建 & 添加

答案:

onCreate:PhoneWindow、DecorView 创建

onResume(handleResumeActivity):

调用 wm.addView,窗口真正显示到屏幕。

2. Dialog 与 Activity 窗口区别?非 Activity 上下文报错原因

答案:

Dialog 是 子窗口,必须依附 Activity 窗口。

Activity 窗口有 AppToken,Dialog 使用宿主 Token。

用 Application 等无 Token 的 Context:

系统校验 Token 失败 → 抛出 WindowManager.BadTokenException。

3. Toast 窗口类型 & 限制 & 崩溃原因

答案:

类型:TYPE_TOAST(系统窗口)

限制:

自动超时消失

高版本无法自定义 Toast

后台弹出受限

常见崩溃:

Toast 持有 Activity 引用导致销毁时窗口泄漏

7.1 以下 Toast 内部 TN 类 Binder 泄漏导致崩溃

4. 悬浮窗权限校验逻辑

答案:

系统窗口类型需要 SYSTEM_ALERT_WINDOW 权限。

Android 6.0+ 动态申请。

Android 10+ 后台弹悬浮窗进一步受限。

WMS 会检查:类型 + 权限 + Token。

5. Dialog 依赖 Activity Window?脱离 Activity 展示要解决什么

答案:

Dialog 是子窗口,必须绑定 Activity Token。

脱离 Activity 需要:

使用 系统窗口类型

申请悬浮窗权限

自己管理生命周期,防止窗口泄漏

五、Surface 与窗口渲染

1. Window 与 Surface 关系 & 窗口渲染流程

答案:

Surface 是一块 画布(缓冲区),Window 对应一个 Surface。

渲染流程:

App 绘制 → 写入 Surface → 提交给 SurfaceFlinger → SurfaceFlinger 合成 → 屏幕显示。

2. SurfaceFlinger 作用 & 与 WMS、App 协作

答案:

SurfaceFlinger:系统合成服务,负责 所有图层混合、合成、送显。

WMS 告诉 SF 窗口位置、大小、层级。

App 往 Surface 里写数据。

SF 按 Z 序合成所有窗口,输出到屏幕。

3. 硬件加速 & 开启后渲染变化

答案:

硬件加速:使用 GPU 绘制 View。

变化:

绘制性能大幅提升

绘制模型变成 显示列表(DisplayList)

部分 API 不兼容或行为改变

4. SurfaceView、TextureView 与普通 View 区别

答案:

普通 View:共享同一个 Surface,在主线程绘制。

SurfaceView:独立 Surface,可子线程绘制,效率高,但不支持动画、平移旋转。

TextureView:有独立缓冲,但挂载在应用窗口中,支持变换、动画。

5. invalidate/requestLayout 如何到 WMS & SF

答案:

invalidate/requestLayout → ViewRootImpl

scheduleTraversals

主线程 performTraversals

measure/layout/draw

绘制内容写入 Surface

setVisible/relayout 通知 WMS

WMS 通知 SF 合成刷新

六、Token 机制与权限校验(字节 / 阿里高频)

1. 为什么用 WindowToken 校验窗口合法性

答案:

防止恶意应用在后台随意弹窗、仿冒界面、窃取隐私。

Token 由系统分发,App 不能伪造。

只有合法 Token 才能创建对应级别窗口。

2. 应用后台弹窗口被拦截核心逻辑

答案:

高版本 Android 限制后台应用弹出覆盖层窗口。

WMS 检查:

应用是否在前台

是否有特殊权限

窗口类型是否允许后台显示

无权限则拒绝 addView。

3. 不同版本对 Token、后台弹窗的改动

答案:

Android 6.0:悬浮窗动态权限

Android 8.0:Toast 改用 TYPE_TOAST,禁止自定义 Toast

Android 10/11:严格限制后台悬浮窗、后台弹出 Activity

整体趋势:越来越严,越安全

4. Application 上下文创建 Dialog 崩溃原因

答案:

Application Context 没有 Activity Token。

Dialog 是子窗口,必须依附带 Token 的 Activity 窗口。

WMS 校验 Token 为空 → 直接抛异常。

5. 如何绕过 Token 实现后台弹窗?系统如何修复

答案:

早期利用 系统漏洞 / 反射 伪造 Token。

利用 TYPE_SYSTEM_ALERT 等系统窗口。

系统修复:

严格权限

严格 Token 校验

后台弹出限制

高版本无法通用绕过

七、多窗口、分屏、折叠屏

1. 多窗口下 WMS 如何管理应用窗口

答案:

WMS 为每个窗口分配 固定区域。

每个应用视为独立窗口栈。

焦点、输入、尺寸单独管理。

生命周期与正常 Activity 略有区别(如不总是 onStop)。

2. 分屏下窗口尺寸、生命周期、焦点变化

答案:

尺寸:按分屏比例重新 layout

生命周期:不会正常走 onStop,保持 resumed

焦点:同一时间只有一个窗口获焦

3. 折叠屏切换时窗口重建与布局

答案:

折叠 / 展开 → 屏幕尺寸变化

系统触发 configChange

默认重建 Activity

可通过 android:configChanges 避免重建,自己重布局

4. 多窗口与 Activity 启动模式关系

答案:

多窗口下,standard 等模式会在 对应窗口栈 内创建。

分屏时,新 Activity 默认在同半屏打开。

特殊启动模式(如 singleInstance)会独占一个窗口。

八、异常场景与问题排查

1. WindowLeaked 场景 & 如何避免

答案:场景:

Activity 销毁时,Dialog/Toast/ 悬浮窗未关闭

窗口仍持有 Activity 引用

避免:

onDestroy 中 dismiss Dialog

用 Application 生命周期管理全局弹窗

及时 removeView

2. 后台切回黑屏 / 白屏与窗口机制关系

答案:

Activity 被销毁后重新创建

DecorView 未完成绘制前显示窗口背景

或 Surface 未准备好

优化:设置合适背景、优化启动、防止不必要重建

3. 窗口动画卡顿、黑屏分析角度

答案:

主线程阻塞,绘制不及时

动画复杂,GPU 负载高

窗口层级过多,SF 合成压力大

Surface 创建 / 销毁延迟

4. 软键盘弹出挤压布局原理

答案:

输入法是一个系统窗口。

键盘弹出 → WMS 调整应用窗口大小

windowSoftInputMode 控制:

压缩布局

平移布局

不调整

九、大厂开放性问题(简要答案)

1. 窗口从创建到显示全流程

Activity → PhoneWindow → DecorView → ViewRootImpl → WMS → SurfaceFlinger → 屏幕。

2. 全局悬浮窗实现要点

申请悬浮窗权限

使用系统窗口类型

处理触摸、拖动、焦点

注意生命周期,防止泄漏

3. 系统窗口与应用窗口通信

Binder、AIDL、ContentProvider、广播。

4. 优化 Activity 窗口启动速度

减少布局层级

异步加载

优化绘制

避免主线程耗时

复用窗口 / 预创建 DecorView

5. Android 12+ 窗口核心改动

统一窗口类型

更严格的后台弹出限制

强化隐私权限

折叠屏 / 大屏增强

相关推荐
萍萍学习2 小时前
蓝桥杯JAVA-4
java·职场和发展·蓝桥杯
XiYang-DING2 小时前
【LeetCode】LCR 019. 验证回文串 II
算法·leetcode·职场和发展
用户013201436033 小时前
Android 资源管理与常用布局详解|基础入门
android
indexsunny3 小时前
互联网大厂Java面试:从Spring Boot到微服务的逐步挑战
java·数据库·spring boot·redis·微服务·面试·电商
陆业聪3 小时前
从 OpenClaw 到 Android:Harness Engineering 是怎么让 Agent 变得可用的
android·人工智能·ai编程
郝学胜-神的一滴3 小时前
冷却时间下的任务调度最优解:从原理到实现
数据结构·c++·算法·面试
List<String> error_P3 小时前
蓝桥杯冲刺(一)
链表·职场和发展·蓝桥杯
酉鬼女又兒3 小时前
零基础快速入门前端DOM 元素获取方法详解:从代码到实践(可用于备赛蓝桥杯Web应用开发)
前端·javascript·职场和发展·蓝桥杯·js
czlczl200209254 小时前
Dijkstra实现
面试