Window在实际开发中使用的不是很多,不过,一些特殊需要使用Window去实现。比如,在桌面上显示一个悬浮窗,就需要使用到Window。
Window是一个抽象类,它只有一个具体实现类PhoneWindow。创建Window需要使用到WindowManager,它是外界访问Window的入口,不过,对Window的具体操作是由WindowManagerService实现的,WindowManager和WindowManagerService通过Binder进行交互。
Android中所有的视图都是通过Window来呈现的,比如Activity、Dialog和Toast等,它们的视图实际上都是附加在一个Window上,因此,Window实际上是View的直接管理者。
Window的使用
下面代码展示了通过WindowManager添加Window的过程:
1 | private Button mFloatingButton; // Window要展示的View |
如果Window需要能够被拖拽,那么需要为Window的View设置监听器:
1 | mFloatingButton.setOnTouchListener(new View.OnTouchListener() { |
在使用Window过程中,需要注意WindowManager.LayoutParams中的flags和type参数,下面分别进行说明。
flags参数表示Window的属性,可以控制Window的显示特性,常用的选项有:
- FLAG_NOT_FOCUSABLE
表示Window不需要获取焦点,也不需要接收各种输入事件,此标记会同时启用FLAG_NOT_TOUCH_MODAL,最终输入事件会传递给下层具有焦点的Window。
- FLAG_NOT_TOUCH_MODAL
在此模式下,系统会将当前Window区域以外的单击事件传递给底层的Window,当前Window区域以内的单击事件则自己处理。一般来说都需要开启此标记,否则其他Window无法接收到单击事件。
- FLAG_SHOW_WHEN_LOCKED
开启此模式可以让Window显示在锁屏的界面上。
type参数表示Window的类型,一共有三种类型:应用Window、子Window和系统Window。应用Window对应一个Activity;子Window不能单独存在,需要附属在特定的父Window上,比如Dialog;系统Window需要声明对应的权限才能被创建,比如Toast和StatusBar。
另外,Window是分层的,每个Window都有层级,层级大的会覆盖在层级小的Window上面。在上面介绍的三类Window中,应用Window的层级范围是1~99,子Window的层级范围是1000~1999,系统Window的层级范围是2000~2999,而这些层级范围对应相应的type参数值。如果使用系统层级,需要声明相关权限,比如使用TYPE_SYSTEM_ERROR系统层级,要声明
Window的原理
WindowManager介绍
WindowManager是操作Window的入口,它只提供了三个方法分别用于添加View、更新View和删除View,这三个方法定义在ViewManager中,而WindowManager继承于ViewManager。
1 | public interface ViewManager |
因此,WindowManager操作Window本质上是操作Window中的View。
Window的内部机制
Window是一个抽象的概念,每一个Window都对应一个View和一个ViewRootImpl,Window和View通过ViewRootImpl建立联系。因此,Window并不实际存在,它是以View的形式存在的。在实际使用中无法直接访问Window,而是要通过WindowManager访问。
Window是通过WindowManager进行操作的,它是一个接口,具体实现是WindowManagerImpl类。WindowManagerImpl并没有直接实现Window的具体操作,而是交给WindowManagerGlobal处理。在WindowManagerGlobal中,会创建View对应的ViewRootImpl对象,通过ViewRootImpl对象实现View的添加、更新和删除操作。不过,ViewRootImpl对View操作最终通过IPC方式交由WindowManagerService进行处理。