Window、WindowManager、WMS区别
Window:
Window 是 Android 中的一个视图容器,代表整个屏幕或 Activity 的一部分。每个 Window 都有自己的 Surface 对象,Surface 对象具有绘制和渲染功能,可以显示 View 和其他元素。在 Android 应用程序中,我们可以使用 setContentView() 方法设置一个布局文件来创建 Window。
WindowManager:
WindowManager 是一个系统服务,主要负责管理所有窗口(Window)的显示和相关操作。通过 WindowManager,我们可以访问当前显示的所有窗口。WindowManager 是 Android 系统中最核心的窗口管理组件之一,也是我们在 Android 应用程序中实现自定义窗口的基础。
WMS (Window Manager Service):
WMS 是 Android 系统中的一个系统服务,也是 WindowManager 的核心部分,主要负责协调和管理所有的窗口。WMS 确定每个窗口的大小、位置和显示顺序,以及响应用户的输入事件。同时,WMS 还负责设置窗口的属性,如 type、flag 等,并执行窗口的动画效果。
Window 是布局视图的容器,WindowManager 是管理窗口显示的服务,WMS 是 WindowManager 的核心,用于协调和管理所有的窗口。WindowManager 和 WMS 都是 Android 系统中非常基础和重要的组件,而 Window 则是应用程序布局的基础。
WindowManager 是一个接口,它继承自 ViewManager,ViewManager 中定义了三个抽象方法,分别用于添加、更新和移除 View。而 WindowManager 接口则继承了这三个方法,并为窗口管理器提供了基本的能力。
WindowManagerImpl 是 WindowManager 的实现类,它实现了 WindowManager 接口,并提供了更具体的功能。在 WindowManagerImpl 的实现过程中,它会使用 WindowManagerGlobal 来协调和管理所有的窗口。WindowManagerGlobal 是一个静态单例对象,它在加载 WindowManagerImpl 时就被创建出来,并在整个 Android 系统中负责协调和管理所有窗口的显示和操作。
Window的类型
Window 的类型有很多种,比如应用程序窗口、系统错误窗口、输入法窗口、PopWindow、Toast、Dialog 等。总的来说 Window 分为三大类型,分别是 Application Window(应用程序窗口)
、Sub Window(子窗口)
、System Window (系统窗口)
,每个大类型中又包含了很多种类型,它们都定义在 WindowManager 的静态内部类 LayoutParams 中.
应用程序窗口
应用程序窗口是特定应用程序内部存在的窗口,可以是全屏窗口或者普通窗口。例如,在我们使用浏览器进行网页浏览时,浏览器的应用程序窗口就是全屏窗口;而在我们观看视频时,播放器的应用程序窗口就是普通窗口。应用程序窗口的类型由 WindowManager 类的常量值定义,其 Type 值范围为 1~99,代表着窗口的层级。应用程序窗口可以对应应用程序内不同的 Activity,可以进行添加、删除、修改等操作。
例如:
TYPE_APPLICATION:应用程序窗口,占据整个屏幕。
TYPE_APPLICATION_PANEL:应用程序面板窗口,在应用程序窗口之上,但能被覆盖。
TYPE_APPLICATION_ATTACHED_DIALOG:应用程序附加对话框窗口,与父 Activity 关联,当 Activity 消失时会自动消失。
TYPE_APPLICATION_MEDIA:应用程序媒体窗口,用于播放视频和音频。
子窗口
子窗口是依附于父窗口之上的窗口,不具有独立性。例如,在我们使用微信聊天时,聊天记录的对话框就是子窗口。子窗口的类型也由 WindowManager 类的常量值定义,其 Type 值范围从 1000~1999。子窗口是建立在应用程序窗口之上的,也就是说,他们必须依附于某个应用程序窗口之上,但是他们可以通过 WindowManager.LayoutParams 类的相关参数(如 parent、token 参数)来改变自己的层级,从而达到弹出效果。
例如:
TYPE_APPLICATION_SUB_PANEL:应用程序子面板窗口。
TYPE_APPLICATION_TOP_MOST:应用程序最顶层窗口。
TYPE_SYSTEM_ALERT:系统警告窗口,显示系统级的警报信息,例如低电量警告。
TYPE_TOAST:提示窗口,用于显示简短的消息。
系统窗口
系统窗口是系统级别的窗口,通常用于显示系统级别的信息或者对话框,例如 Toast、输入法窗口、系统音量条窗口、系统错误窗口等。它们都属于系统级别的应用程序,具有比较高的优先级和权限。系统窗口的类型也由 WindowManager 类的常量值定义,其 Type 值范围为 2000~2999。相对于应用程序窗口和子窗口,系统窗口的层级最高,因此它们总是能够出现在屏幕的最上层,即使是该应用程序的活动窗口正在显示中。
例如:
TYPE_STATUS_BAR:状态栏窗口,显示系统状态,例如时间、电量等。
TYPE_NAVIGATION_BAR:导航栏窗口,是一个系统级别的窗口,用于控制屏幕导航。
TYPE_INPUT_METHOD:输入法窗口,显示用户输入的文本。
TYPE_SYSTEM_OVERLAY:系统覆盖窗口,它可以放置在所有其他窗口的上面。
Window的标志
Window的标志(Flag)是一种用于控制窗口行为的选项,它可以指定窗口是否应该在锁屏界面之上显示、窗口是否自动点亮屏幕等等。
以下是常用的几个Window Flag的介绍:
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
使用该标志后,当窗口可见时,即使设备处于打开状态但在锁屏状态下,仍允许在屏幕上锁屏。这主要是针对一些情况下需要保持屏幕亮着而又不能操作时很有用,比如让用户只观看某些特定内容不可操作,此时屏幕保持亮着而不会滑入待机状态。
FLAG_NOT_FOCUSABLE
仅当窗口无须获得输入焦点时,才应设置此标志。设置该标志意味着,当用户触摸并选择该窗口时,该窗口不会接收到任何输入事件。
FLAG_NOT_TOUCHABLE
使用该标志后,窗口将不会响应任何触摸事件。
FLAG_NOT_TOUCH_MODAL
指定窗口在处理触摸事件时,是否限制在当前窗口内。如果使用这个标志,则该窗口外的任何触摸事件都将被传递给下面的窗口。
FLAG_KEEP_SCREEN_ON
该标志确保屏幕保持开启状态,直到从当前窗口移除或清除FLAG_KEEP_SCREEN_ON标志。
FLAG_LAYOUT_NO_LIMITS
使用该标志可以使窗口超出屏幕尺寸而不会被截断。这个标志通常用于应用程序需要在特殊情况下覆盖全屏幕的场景。
FLAG_FULLSCREEN
指定窗口在全屏模式下呈现,隐藏状态栏和导航栏。比如在游戏和视频播放时使用。
FLAG_SHOW_WHEN_LOCKED
使用该标志后,即使设备处于锁屏状态,该窗口也能显示在锁屏界面之上。这个标志通常使用于闹钟、电话来电等应用场景。
FLAG_IGNORE_CHEEK_PRESSES
当用户在通话过程中将自己的脸靠近屏幕时,该标志告知系统不要响应触摸事件。这个标志通常用于防止带有接近检测芯片的设备因触摸而产生额外的误操作。
FLAG_TURN_SCREEN_ON
此标志允许屏幕在显示窗口时点亮,以确保接收到最新信息,例如来电提醒等。
设置 Window 的 Flag 有 3 种方法
通过 Window 的 addFlag 方法
该方法用于向 Window 中添加一个 Flag,每次调用该方法只能添加一个 Flag。若要添加多个 Flag,需要多次调用该方法。
Window mWindow = getWindow();
mWindow.addFlag(WindowManager.LayoutParams.FLAG_FULLSCREEN);
需要注意的是,该方法添加的 Flag 仅在当前 Activity 或对话框打开时有效,当 Activity 或对话框关闭后,添加的 Flag 也会被清除。
通过 Window 的 setFlags 方法
该方法用于设置 Window 的 Flag,可以同时设置多个 Flag,将多个 Flag 通过按位或操作进行合并即可。该方法可以用于在 Activity 创建后、onCreate 方法调用前进行 Flag 的设置。
Window mWindow = getWindow();
mWindow.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN)
使用该方法需要注意,若要给 Window 设置多个 Flag,需将所有 Flag 合并后再传入第二个参数中,而不能像 addFlag 方法一样逐个添加。
给 LayoutParams 设置 Flag, 并通过 WindowManager 的 addView 方法进行添加
该方法一般用于在系统级别的 View 上设置 Flag,例如悬浮窗。我们需要创建一个 WindowManager.LayoutParams 实例,然后将需要的 Flag 设置到该实例的 flags 属性中,最后通过 WindowManager 的 addView 方法将 View 添加到窗口中。
WindowManager.LayoutParams mWindowLayoutParams = new WindowManager.LayoutParams();
mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN;
WindowManager mWindowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
Text mText = new Text(this);
mWindowManager.addView(mTextView,mWindowLayoutParams);
需要注意的是,该方法添加的 Flag 仅在 View 显示期间有效,当 View 移除后,添加的 Flag 也会被清除。