写点什么

Android 窗口管理,2021Android 大厂面试经验分享

作者:嘟嘟侠客
  • 2021 年 11 月 27 日
  • 本文字数:3352 字

    阅读完需:约 11 分钟

4.??????焦点窗口和焦点应用的管理


5.??????输入法窗口管理和墙纸窗口管理


6.??????转场动画


7.??????系统消息收集和分发


服务端的实现代码是在/framework/base/services/java/com/android/server/wm/里,核心的几个类是:


WindowManagerService.java


WindowState.java


WindowToken.java


AppWindowToken.java


Session.java


InputManager.java


InputMonitor.java


类解释:


WindowManagerService 负责完成窗口的管理工作;


WindowState 和客户端窗口一一对应,应用调用 WindowManager.addView()时,最终会在 WindowManagerService 添加一个 WindowState 与之一一对应。


WindowToken 是一个句柄,保存了所有具有同一个 token 的 WindowState。应用请求 WindowManagerService 添加窗口的时候,提供了一个 token,该 token 标识了被添加窗口的归属,WindowManagerService 为该 token 生成一个 WindowToken 对象,所有 token 相同的 WindowState 被关联到同一个 WindowToken。如输入法添加窗口时,会传递一个 mCurrToken,墙纸服务添加窗口时,会传递一个 newConn.mToken。


AppWindowToken 继承于 WindowToken,专门用于标识一个 Activity。AppWindowToken 里的 token 实际上就是指向了一个 Activity。ActivityManagerService 通知应用启动的时候,在服务端生成一个 token 用于标识该 Activity,并且把该 token 传递到应用客户端,客户端的 Activity 在申请添加窗口时,以该 token 作为标识传递到 WindowManagerService。同一个 Activity 中的主窗口、对话框窗口、菜单窗口都关联到同一个 AppWindowToken。


Session 表示一个客户端和服务端的交互会话。一般来说不同的应用通过不同的会话来和 WindowManagerService 交互,但是处于同一个进程的不同应用通过同一个 Session 来交互。


InputManager 和 InputMonitor 负责上层的消息分发功能。


WindowManagerService 内部的几个重要成员变量:


ArrayList<WindowState>???????? mWindows


HashMap<IBinder, WindowState> ??????? mWindowMap


ArrayList<WindowToken>??????? mTokenList


ArrayList<AppWindowToken> ??????? mAppTokens


mWindows 保存了系统中所有的 WindowState;


mWindowMap 保存了每个 WindowState 和客户端窗口的映射关系,客户端应用请求窗口操作时,通过 mWindowMap 查询到对应的 WindowState;


mTokenList 保存了所有的 WindowToken


mAppTokens 保存了所有的 AppWindowToken


![](https://img-my.csdn.net/uploads/201


《Android 学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享


208/18/1345221092_3080.png)


窗口管理服务端主要类图


一个 Activity 从启动到添加窗口的整个流程如下:


ActivityManagerService 在接收到启动 Activity 请求时,首先生成一个 token 作为该 Activity 的唯一标识。然后调用 WindowManagerService 向其添加一个 AppWindowToken,此 AppWindowToken 封装了 Activity 的 token。接着 AMS 启动应用客户端进程并把 token 传递到该进程,在客户端进程里完成 Activity 的初始化。在 Activity 的 attach()函数中,Activity 完成 PhoneWindow 的创建,并且把 token 传递给 PhoneWindow。在 Activity 调用 WindowManager.addView()时,在 WindowManager 内部会把 token 和该 View 关联,真正向 WindowManagerService 申请创建窗口的时候,再把 token 传递给 WindowManagerService。WindowManagerService 接收到创建窗口的请求的时候,通过 mTokenMap 查询对应该 token 的 AppWindowToken,如果为空则抛出异常,否则创建一个 WindowState 并完成初始化工作和其他数据结构的调整工作。在这个过程中,token 贯穿了服务端的 AMS、WMS 和客户端的 Activity、Window。



Activity 启动过程中创建窗口的时序图


四、????????????WMS 中服务端和客户端的交互接口和数据结构


应用请求创建窗口时,和应用直接交互的是 WindowManager 对象。WindowManager 只是一个接口,调用 addView()创建窗口时正真交互的是 WindowManagerImpl 对象。WindowManagerImpl 管理单个应用的所有本地窗口。应用调用 addView()创建窗口时,WindowManagerImpl 会生成一个 ViewRoot 对象与之相对应,并且把相应的参数 LayoutParams 保存起来。


addView()的执行流程如下:


(1)????检查所添加的窗口是否已经添加过,不允许重复添加;


(2)????如果所添加窗口为子窗口类型,找到其父窗口,并保存在内部变量中;


(3)????创建一个新的 ViewRoot,并保存对应的 View(DecorView)和 LayoutParams;


(4)????调用 ViewRoot 的 setView()方法,完成真正意义上的添加工作。


ViewRoot 本质上是一个 Handler,并且实现了 ViewParent 接口。ViewRoot 的主要功能是:


1.??????负责分发消息事件,如 Key、Motion 事件等;


2.??????负责和 WMS 的交互,分发 WMS 的交互命令;


3.??????作为 DecorView 的 parent,对 DecorView 进行 draw、measure、layout 等操作;


在 addView()的第 3、4 步完成之后,ViewRoot 就全权接管了和 WMS 的交互工作,DecorView 不需要做任何交互动作。ViewRoot 和 WMS 之间的双向对话,主要是通过以下两个数据结构进行的:


IWindowSession


IWindow


这两个数据结构都是标准的 aidl 接口,用于进程之间的同步通信。IWindowSession 负责 ViewRoot 到 WMS 的单向请求,IWindow 则用于 WMS 回调 ViewRoot。在 ViewRoot 对象内部,存在着一个 IWindowSession 的静态成员和一个 IWindow 的非静态成员,所以一个进程里只有一个 IWindowSession 对象,但是可以有多个 IWindow 对象。


Window、WindowManager、DecorView、ViewRoot、IWindowSession、IWindowSession、WindowState、WindowManagerService 之间的关系可用下图来表示:



在 ViewRoot 的构造函数中,调用 getWindowSession()初始化静态成员 sWindowSession 和非静态成员 mWindow。在第 4 步调用 setView()方法时,ViewRoot 会调用 sWindowSession.add()方法,把 IWindow 添加到 WMS 中,WMS 就会生成一个 WindowState 与之一一对应,并且把 IWindow 对象保存到 WindowState 内部作为回调的接口。之后所有 WMS 的命令,都会通过直接访问 IWindow 接口,以消息的形式分发到 ViewRoot,ViewRoot 来完成相应的处理,或对 DecorView 进行操作,或完成后通过 sWindowSession 报告给 WMS。


一个窗口从添加到显示可用以下时序图表示:



窗口添加过程时序图


到此为止,整个窗口管理系统整体架构可表示如下:



窗口管理系统整体架构图


五、????????????WindowState 和 Surface


从 Client 端调用 WindowManager 的 addView()方法到 WMS 完成 WindowState 的初始化,在这整个过程中,只是完成了一个窗口数据结构的创建,也就是说,到现在为止,Client 端的窗口和 Server 端的窗口已经建立了一种相对固定的连接关系,并且 Client 端和 Server 端之间能够正常通信,WMS 能够透明的对 Client 端的窗口进行操作,同时 WMS 也能够接收 Client 端窗口的命令,对 WindowState 进行相应的调整。


一个 WindowState 想要显示在屏幕上,必须申请一个显示缓存,这个显示缓存的管理和维护是在底层图形模块实现的,在 java 层有一个操作的封装对象 Surface。WindowState 申请到 Surface 对象之后,会将此 Surface 对象的相关数据拷贝到 Client 端的 ViewRoot 中,ViewRoot 中也维护了一个 Surface 对象,实际上这两个对象是指向同一块显示缓存。ViewRoot 有了这块显示缓存的引用之后,即可以通过 lockCanvas 来获取绘画画布,绘制完毕之后通过 unlockAndPostCanvas 来将绘制内容刷新到显示缓存中。也就是说,Client 端窗口和 Server 端窗口共用一个 Surface,Client 负责绘制 Surface 的内容,Server 负责控制 Surface 在屏幕上的大小位置等。


ViewRoot 通过 IWindowSession 的 relayout()接口来向 WMS 发送请求命令,包括窗口的显示和隐藏,窗口的布局信息如位置大小,同时还会接收 WMS 的处理结果。WMS 会根据屏幕大小和 Client 请求的布局参数来决定窗口最终的布局信息,同时也会根据 Client 请求的显示隐藏命令来返回一个有效的或者无效的 Surface 对象。通常一个窗口的显示过程为:

最后

只要是程序员,不管是 Java 还是 Android,如果不去阅读源码,只看 API 文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。


真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。



腾讯、字节跳动、阿里、百度等 BAT 大厂 2019-2021 面试真题解析



资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图


本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

用户头像

嘟嘟侠客

关注

还未添加个人签名 2021.03.19 加入

还未添加个人简介

评论

发布
暂无评论
Android窗口管理,2021Android大厂面试经验分享