本文内容参考:Android 核心分析(13) —–Android GWES之Android窗口管理
上一篇文章主要讲述了窗口的基本结构,那么在这样的结构下,系统如何管理窗口,如何下发事件,如何获取窗口状态?这篇博客将对这部分的内容进行介绍。
Android在窗口管理上采用了最为经典的C/S模式,Client端是各个Activity中的window,而Service端就是系统持有的窗口管理器Window Manager。
总体结构
Window
是顶级的窗口概念,而Activity
中的DecorView
则是窗口中的顶级View
,创建Activity
时,DecorView
会attach到Activity
的窗口中,同时也被加入到WindowManager
中,WindowManager
使用WindowState
与该View
相对应。
两者之间通过建立session会话进行通信,而这里的session采用的还是Android中最重要的IPC方式——AIDL。Activity
在建立窗口后需要将该窗口注册到WindowManager
中,这个过程涉及到在Activity
本地创建一个WindowManager
的代理,Activity
通过这个代理和远程WindowManager
进行会话,会话的通道是IWindowSession
,本质上就是一个AIDL通信过程。
会话是双向的,为了将消息发送给对应的Window
,WindowManager
通过IWindow
接口将对应的消息发送给Window
端对应的处理函数。
Client端——Activity
首先来看一下Client
端,通过我的上一篇博客Android窗口管理(1)——窗口基本架构我们知道了Activity
端的窗口结构,并且知道了Window
,PhoneWindow
都不是很重要的概念,实际真正干事的还是ViewRoot
。Activity
在创建的时候会调用onAttach()
创建PhoneWindow
这个类,并在handleResumeActivity
时将窗口加入到WindowManager
中,不过加入的实际上并不是窗口,而是DecorView
。所以其实在客户端的核心概念只有ViewRoot
,DecorView
以及ViewGroup
。其中后面两者主要还是View
的概念,真正完成与WindowManager
进行通信的还是ViewRoot
这个家伙。
ViewRoot
ViewRoot
的真正实现类是ViewRootImpl
。ViewRoot
通过与WindowManager
进行通信完成addView
以及消息下发。ViewRoot
通过IWindowSession
将窗口加入到WindowManager
中。 WindowManager
通过IWindow
接口下发事件到Activity
。
所以ViewRoot
其实本质上是一个Handler
,用于接收消息并处理消息。 Activity
利用getSystemService
来获取WindowManagerImpl
实例,而这个实例实际上就是WindowManager
在客户端本地的代理:
wm=(WindowManagerImpl)context.getSystemService(Context.WINDOW_SERVICE);
之后再调用addView
接口通过WindowManagerImpl
将窗口添加到WindowManager
中。在addView
的过程中,WindowManagerImpl
会建立起View
,Layout
,ViewRoot
之间的对应关系,然后利用IWindowSession
传递给WindowManager
。
Server端——WindowManager
WindowManager
是服务端管理窗口的组件,它管理的是各个应用的顶级窗口,也即DecorView
。将所有的窗口归置到一个统一的系统服务WindowManagerService
管理是Android系统的设计思想,这样的机制并不难理解,系统总要有一个总管各个窗口的管家嘛,总不能任其自生自灭。WindowManagerService
的主要工作包括:
Window Service大体上实现了如下的功能:,
(1)Z-ordered的维护函数
(2)输入法管理
(3)AddWindow/RemoveWindow
(4)Layerout
(5)Token管理,AppToken
(6)活动窗口管理(FocusWindow)
(7)活动应用管理(FocusAPP)
(8)转场动画
(9)系统消息收集线程
(10)系统消息分发线程
在服务端窗口对象叫作WindowState
,Server端维护一个mWindow
,其实就是一个按Z-order排序的窗口数组。mWindowMap
用于记录<Client:Binder,WindowState对象>
。 WindowState
通过本地的client
实例维护IWindow
实例,同时利用该实例访问窗口。
FocusWindow活动窗口如何计算
原理其实很简单,首先找到前台应用,然后根据mWindow
找到Z-order顺序中第一位次的窗口,该窗口就是活动窗口。
为什么要提出Token这个概念
Token在本质上就是一个标示符,应用程序使用改标示符来找到该应用的窗口。AppToken:<Token:IBinder,allWindows>
。通过Token就可以管理该应用的所有窗口。
WindowManager
消息与分发
下面再来说一下WindowManager
的系统消息收集与分发过程。WindowManagerService
在内部维护了一个KeyQ
的消息队列,同时还有两个线程:
1.InputDeviceReader
2.InputDispatcherThread
InputDeviceReader
使用Native函数readEvent
从driver中读取RawEvent
并放到KeyQ
队列中。 InputDispatherThread
负责从KeyQ
队列中读取事件,并在WindowManager
找到对应的窗口,利用该窗口的IWindow
接口下发事件。