8.1 Window和WindowManager
Window表示的是一个窗口的概念,它的具体实现是PhoneWindow,创建一个Window很简单,只需要WindowManager去实现,WindowManager是外界访问Window的入口,Window的具体实现是在WindowManagerService中,他们两个的交互是一个IPC的过程,Android中的所有视图都是通过Window来实现的。
Flag参数
- FLAG_NOT_FOCUSABLE
- 表示窗口不需要获取焦点,也不需要接收各种事件,最终的事件会传递给下层的具体焦点的window
- FLAG_NOT_TOUCH_MODAL
- 在此模式下,系统会将当前window区域以外的单击事件传递给底层的Window,此前的Window区域以内的单机事件自己处理,
- FLAG_SHOW_WHEN_LOCKED
- 开启这个属性可以让window显示在锁屏上
Type参数表示window的类型,window有三种类型,分别是应用,子,系统,应用window对应一个Activity,子Window不能单独存在,需要依赖一个父Window。
Window是分层的,每个Window对应着z-ordered,层级大的会覆盖在层级小的Window上面,这和HTML中的z-index的概念是一致的,在这三类中,应用是层级范围是1-99,子window的层级是1000-1999,系统的层级是2000-2999。这些范围对应着type参数,如果想要window在最顶层,那么层级范围设置大一点就好了,很显然系统的值要大一些,系统的值很多,我们一般会选择TYPE_SYSTEM_OVERLAY和TYPE_SYSTEM_ERROR,还需要声明权限。
WindowManager所提供的功能很简单,常用的有三个方法,添加View,更新View,删除View,这三个方法定义在ViewManager中,而WindowManager继承自ViewManager。
public interface ViewManager {
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
我们常见的可以拖动的View,其实也很好实现,就是不断的更改他xy的位置:
btn.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int rawX = (int) event.getRawX();
int rawY = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
layout.x = rawX;
layout.y = rawY;
wm.updateViewLayout(btn,layout);
break;
}
return false;
}
});
8.2 Window的内部机制
Window是一个抽象的概念,每一个Window都对应着一个View和一个ViewRootlmpl,Window和View通过ViewRootImpl 来建立联系,因此Window并不是实际存在的,它是以View的形式存在。这点从WindowManager的定义也可以看出,它提供的三个接口方法addView、updateViewLayout以及removeView都是针对View的,这说明View才是Window存在的实体。在实际使用中无法直接访问Window, 对Window 的访问必须通过WindowManager。为了分析Window的内部机制,这里从Window的添加、删除以及更新说起。
8.2.1 Window的添加过程
WindowManagerImpl并没有直接去实现一个Window的三大操作,而是全部交给了WindowManagerGlobal来处理,WindowManagerGlobal是一个工厂的性质提供自己的实现。WindowManagerImpl这种工作模式就是典型的桥接模式,将所有的操作全部委托给WindowManagerGlobal去实现,WindowManagerGlobal的addView方法主要分如下几步:
- 检查参数是否合法,如果是子Window还需要调整一下参数
- 创建ViewRootImpl并将View添加到列表中
- 通过ViewRootImpl来更新界面并完成Window的添加