Window的添加过程需要通过WindowManager的addView来实现,WindowManager是一个接口,真正的实现是WindowManagerImpl。而WindowManagerImpl全部是转移给WindowManagerGlobal来处理,WindowManagerImpl这种工作模式是典型的桥接模式。WindowManagerImpl内三大操作过程如下:
public void addView(View view,ViewGroup.LayoutParams params){
mGlobal.addView(view,params,mDisplay,mParantWindow);
}
public void updateViewLayout(View view,ViewGroup.LayoutParams params){
mGlobal.updateViewLayout(view,params);
}
public void removeView(View view){
mGlobal.removeView(view,false);
}
从WindowManagerGlobal
名称可以看出,它是一个全局的WindowManager
,其内部维护如下几个列表:
private final ArrayList mViews = new ArrayList();
private final ArrayList mRoots = new ArrayList()
private final ArrayList mParams = new ArrayList();
private final ArraySet mDyingViews = new ArraySet();
其中:
Window
所对应的View
Window
所对应的ViewRootImpl
Window
所对应的布局参数View
对象,或者说是那些已经调用了removeView
方法但是删除操作还未完成的Window
对象addView
中通过如下方式将Window
的一系列对象添加到列表中:
root=new ViewRootImpl(view.getContext(),display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
可以看到,到目前为止,只是把相应的对象存放到ArrayList
列表中。后面还需要将View
给显示出来。绘制View
需要通过ViewRootImpl
的setView
方法来实现。在setView
内部是通过requestLayout
来完成一部刷新请求的。
public void requestLayout(){
if(!mHandlingLayoutInlayoutRequest){
checkThread();
mLayoutRequested=true;
scheduleTraversals();
}
}
其中scheduleTraversals是View绘制的入口!
下面我们看看ViewRootImpl是内部机制。
ViewRootImpl用于管理窗口的根View,并和WMS进行交互。ViewRootImpl中有一个内部类: W,以及另一个内部类:ViewRootHandler。
W
继承自IWindow.Stub
。是一个Binder
对象,用于接收WMS
的各种消息, 如按键消息, 触摸消息等。ViewRootHandler
,是Handler
的子类, W
会通过Looper
把消息传递给ViewRootHandler
ViewRootImpl有一个W类型的成员mWindow,ViewRootImpl在构造函数中创建一个W的实例并赋值给mWindow。
在ViewRootImpl的setView方法(此方法运行在UI线程)中,会通过IPC的方式跨进程向WMS发起一个远程调用,从而将DecorView最终添加到Window上,在这个过程中,ViewRootImpl、DecorView和WMS会彼此向关联.
另外,WMS有时也需要向ViewRootImpl发送远程请求,比如,点击事件是由用户的触摸行为所产生的,因此它必须要通过硬件来捕获,跟硬件之间的交互自然是Android系统自己把握,Android系统将点击事件交给WMS来处理。WMS通过远程调用将事件发送给ViewRootImpl,在ViewRootImpl中,有一个方法,叫做dispatchInputEvent,最终将事件传递给DecorView。
接下来,由WindowSession来完成最后的Window添加过程。mWindowSession本身是一个IWindowSession类型对象,通过内部代理类Proxy访问远程Session类(Binder机制) 。在Session内部通过WMS来实现Window的添加。如此一来Window的添加请求就交给了WMS去处理了,如下图所示:
WindowManagerService
内部为每个应用保留一个单独的Session
,如下图所示:
前面我们说过,每个Window对应一个ViewRootImpl及一个View Tree。也就是说,每个Activity对应的Window(一个或多个)内通过其内置的ViewRootImpl完成向WMS的请求过程。
一个应用中的所有Activity共用一个Session,一个Window在WMS内部对应一个WindowState,WindowState维护窗口的状态以及根据适当的机制来调整窗口的状态。
如果一个Activity多个Window,如对话框、Popup类型、或者通过ViewManager将View直接加入WMS,等等。在这些情况下,一个Activity就会创建多个Window,相应的WMS中也会对应多个WindowState,如下图所示:
以下内容来自老罗的的博客,后面附有资料链接。
WMS
服务大致按照以下方式来控制哪些窗口需要显示的以及要显在哪里:
Activity
窗口的大小都等于屏幕的大小,因此,只要对每一个Activity
窗口设置一个不同的Z
轴位置,然后就可以使得位于最上面的,即当前被激活的Activity
窗口,才是可见的。Activity
窗口及其所弹出的子窗口都可以同时显示出来。Activity
窗口来说,它会在屏幕的上方留出一块区域,用来显示状态栏。这块留出来的区域称对于屏幕来说,称为装饰区(decoration
),而对于Activity
窗口来说,称为内容边衬区(Content Inset
)。Activity
窗口的内容边衬区的。Activity
窗口的下方,这时候要求Activity
窗口是半透明的,这样就可以将它后面的壁纸窗口一同显示出来。参考资料:
1. 【Android窗口管理服务WindowManagerService的简要介绍和学习计划 】
2. 《Android开发艺术探索》
3. 【Android 应用程序建立与WMS服务之间的通信过程】
4. 【Android Window Manager Subsystem Research 】