理解Window和WindowManager
Window是一个抽象类,它的具体实现是PhoneWindow,Window的添加,更新和删除 都是通过WindowManager对应的addView,updateViewLayout,removeVeiw 三个方法实现。外部不需要直接去实例化window.WindowManager最终会和WindowManagerService(WMS)进行交互(IPC过程),来实现Window的添加,更新和删除。常见的Window有,Activity,Dialog,Toast等。
WindowManager
WindowManager 继承与VeiwManager,它的三个重要方法也定义在VeiwManager中。
public interface ViewManager{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
WindowManager.LayoutParams
可以看到,WindowManager的操作Window的方法实际上都是操作的Veiw,View是Window的载体。但虽然我们平时接触的最多的是View,但是View离开了Window,就啥也不是了,无法显示在屏幕上,所以Window是非常重要的抽象概念。扯远了。可以看到,添加View和更新View方法里面都需要用到LayoutParams.
WindowLayoutParams除了常见的一些,x,y,gravity等属性外,还有两个比较重要的属性,flag,type.
Flags
Flag参数表示Window的属性,它有很多选项,通过这些选项合一控制Window的显示特性
-
FLAG_NOT_FOCUSABLE 表示Window不需要获取焦点
-
FLAG_NOT_TOUCH_MODAL 在此模式下,系统会将当前window区域外的单击事件传递给底层window。当前区域以内的单击事件则自己处理。
-
FLAG_SHOW_WHEN_LOCKED 开启此模式可以让Window显示在锁屏的界面上
Type
Type 表示window的类型,window有三种类型,分别是应用window,子window,系统window。应用window对应着一个Activity.子window不能单独存在,他需要附属在特定的父window上,比如Dialog。系统window则需要申明权限才能创建。比如Toast和系统状态栏。
Window是分层的,层级高的window会覆盖在层级低的window上。
Window的内部机制
Window 是一个抽象概念。每一个Window对应一个View 和一个ViewRootImpl,Window和Veiw通过VeiwRootImpl来建立联系。因此Window并不是实际存在的,他是以View的形式存在。这点可以从WindowManager的定义也可以看出。他提供的三个接口方法都是以View命名。实际使用过程中也无法直接访问Window,对window的访问必须通过WindowManager。
Window的添加
WindowManager->WindowManagerImpl->WindowManagerGlobal。通过源码我们可以看到添加删除,修改三大方法最终都交到了WindowManagerGlobal中,这是一种典型的桥接模式。将所有的操作都委托给WindowManagerGlobal来实现。
在WindowManagerGlobal的addView方法中,大致可以分为三步。
-
检查参数是否合法,如果是子Window还需调整一些布局参数
-
创建VeiwRootImpl并将Veiw添加到列表中。
-
通过VeiwRootImpl的setView方法来更新界面以及添加到WindowServiceManager中。
在WindowManagerGlobal内部维护着几个列表比较重要。
private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
private final ArrayList<WindowManager.LayoutParams> mParams =
new ArrayList<WindowManager.LayoutParams>();
private final ArraySet<View> mDyingViews = new ArraySet<View>();
mViews 存储的是所有Window对应的View,mRoots存储的是所有Window对应的ViewRootImpl,mParams存储的是所有Window对应的布局参数,而mDyingViews存储的是那些正在被删除的ViewD对象。
Window的删除
最终也是通过ViewRootImpl来完成的,die方法最终会通过WindowSession的remove方法,调用到WindowManager的removeWindow方法。
Window的更新
最终也是调用到了ViewRootImpl的setLayoutParams方法。在ViewRootImpl中还是通过WindowSession访问到了WindowManagerService的relayoutWindow来更新window。
Window的添加,删除,更新的总结。
从WindowManager开始,到ViewRootImpl,到WindowSession,到WindowManagerService。到WMS这一步就是IPC过程了,想想也能明白,在我们的应用中调用了一个方法,到屏幕上显示变化等操作,肯定是需要跨进程的。