理解Window和WindowManager

1,184 阅读3分钟

理解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过程了,想想也能明白,在我们的应用中调用了一个方法,到屏幕上显示变化等操作,肯定是需要跨进程的。