一、Window介绍
Window,即窗口,在 Android 中,它是一个抽象的东西,我们在日常开发中,直接接触到的东西是 View,而 View 是附着在 Window 之上的。所以我们也可以说 Window 是 View 的直接管理者。
二、Window的相关属性
window的窗口属性
虽然Android系统中的窗口非常多,不过从用途来考虑,我们可以将其分为三大类:
Application Window
System Window
Sub Window
细分的若干子类型都能从WindowManager.java中找到,接下来用表格详细展示window窗口的属性
Application Window
普通应用程序的窗口都属于这一类
Type | Description |
---|---|
FIRST_APPLICATION_WINDOW=1 | 应用程序窗口类型的起始值 |
TYPE_BASE_APPLICATION=1 | 应用程序窗口类型的基础柱,其他窗口类型一次为基础 |
TYPE_APPLICATION=2 | 普通应用程序窗口类型 |
TYPE_APPLICATION_STARTING=3 | 应用程序的启动窗口类型,应用程序本身不可使用,Android系统自动为应用程序启动前展示的窗口,当应用程序启动后就会消失 |
LAST_APPLICATION_WINDOW=99 | 应用程序窗口类型的最大值 |
Sub Window
见名知意,子窗口,附着在某些窗口中,包括下列一些子类型
Type | Description |
---|---|
FIRST_SUB_WINDOW=1000 | 子窗口类型的起始值 |
TYPE_BAPPLICATION_PANEL=FIRST_SUB_WINDOW | 应用程序的panel子窗口,在它的父窗口之上显示 |
TYPE_APPLICATION_MEDIA=FIRST_SUB_WINDOW+1 | 用于显示多媒体内容的子窗口,位于父窗口之下 |
TYPE_APPLICATION_SUB_PANEL=FIRST_SUB_WINDOW+2 | 也是panel子窗口,位于父窗口以及所有TYPE_APPLICATION_PANEL子窗口之上 |
TYPE_APPLICATION_ATTACHED_DIALOG=FIRST_SUB_WINDOW+3 | Dialog子窗口,类似menu类型 |
TYPE_APPLICATION_MEDIA_OVERLAY=FIRST_SUB_WINDOW+4 | 多媒体窗口的覆盖层,位于TYPE_APPLICATION_MEDIA和应用程序窗口之间,通常透明才有意义,未开放 |
TYPE_SUB_WINDOW=1999 | 子窗口类型的结束值 |
System Window
系统窗口,包括下列一些子类型
Type | Description |
---|---|
FIRST_SYSTEM_WINDOW=2000 | 系统窗口类型的起始值 |
TYPE_STATUS_BAR=FIRST_SYSTEM_WINDOW | 系统状态栏窗口 |
TYPE_SEARCH_BAR=FIRST_SYSTEM_WINDOW+1 | 搜索条窗口 |
TYPE_PHONE=FIRST_SYSTEM_WINDOW+2 | 通话窗口,一般来电通话位于系统状态栏之下,其他应用窗口之上 |
TYPE_SYSTEM_ALERT=FIRST_SYSTEM_WINDOW+3 | Alert窗口,如电量不足的警告窗口,一般位于所有其他应用程序之上 |
TYPE_KEYGUAED=FIRST_SYSTEM_WINDOW+4 | 屏保窗口 |
TYPE_TOAST=FIRST_SYSTEM_WINDOW+5 | 短暂提示框窗口 |
TYPE_SYSTEM_OVERLAY=FIRST_SYSTEM_WINDOW+6 | 系统覆盖层窗口,不可接受input焦点否则会与屏保冲突 |
TYPE_PRIORITY_PHONE=FIRST_SYSTEM_WINDOW+7 | 电话优先窗口,屏保状态下显示来电窗口 |
TYPE_SYSTEM_DIALOG=FIRST_SYSTEM_WINDOW+8 | RecentAppsDialog就是这种类型窗口 |
TYPE_KEYGUARD_DIALOG=FIRST_SYSTEM_WINDOW+9 | 屏保时显示的对话框 |
TYPE_SYSTEM_ERROR=FIRST_SYSTEM_WINDOW+10 | 系统错误窗口 |
TYPE_INPUT_METHOD=FIRST_SYSTEM_WINDOW+11 | 输入法窗口 |
TYPE_INPUT_METHOD_DIALOG=FIRST_SYSTEM_WINDOW+12 | 输入法窗口之上的对话框窗口 |
TYPE_WALLPAPER=FIRST_SYSTEM_WINDOW+13 | 壁纸窗口 |
TYPE_STATUS_BAR_PANEL=FIRST_SYSTEM_WINDOW+14 | 滑动状态栏出现的窗口 |
TYPE_NAVIGAGTION_BAR=FIRST_SYSTEM_WINDOW+19 | 导航条 |
TYPE_VOLUME_OVERLAY=FIRST_SYSTEM_WINDOW+20 | 系统音量条 |
TYPE_BOOT_PROGRESS=FIRST_SYSTEM_WINDOW+21 | 启动时的进度条窗口 |
TYPE_HIDDEN_NAV_CONSUMER=FIRST_SYSTEM_WINDOW+22 | 导航条隐藏时用于消费触摸事件的伪窗口 |
TYPE_UNIVERSE_BACKGROUND=FIRST_SYSTEM_WINDOW+25 | 多用户系统中,将显示给所有用户 |
TYPE_DISPLAY_OVERLAY=FIRST_SYSTEM_WINDOW+26 | 用于模拟第二个显示设备 |
TYPE_MAGNIFICATION_OVERLAY=FIRST_SYSTEM_WINDOW+27 | 类似放大镜的效果,用于放大显示某部分内容 |
TYPE_RECENTS_OVERLAY=FIRST_SYSTEM_WINDOW+28 | 与TYPE_SYSTEM_DIALOG基本类似,区别在于TYPE_RECENTS_OVERLAY只显示在一个用户的屏幕上 |
LAST_SYSTEM_WINDOW=2999 | 系统窗口结束 |
每种窗口类型都有一个数值,三类窗口间隔是:
Application Window:1-99
Sub Window:1000-1999
System Window:2000-2999
当某个应用进程向wms申请窗口时,需要指定所需的窗口类型(当然应用程序基本上不允许创建系统窗口,会在权限检查时被拒绝),然后wms根据用户申请的窗口类型以及当前系统中已有窗口的情况给这个窗口最终分配一个"层级值",系统在运行期间,很可能会出现同一种窗口类型当前有很多个窗口,比如当前有三个应用程序在执行,那类型为TYPE_APPLICATION的应用程序窗口就会有3个,因此wms需要根据具体情况调整他们的最终层级值。数值越大的窗口,在wms中优先级就越高,最终在屏幕显示时就越靠近用户。
Window的flags参数
flag控制的范围包括了:各种情景下的显示逻辑(锁屏,游戏等)还有触控事件的处理逻辑。控制显示确实是他的很大部分功能,但是并不是全部。
window的solfInputMode属性
这一部分就是当软件盘弹起来的时候,window的处理逻辑,这在日常中也经常遇到,如:我们在微信聊天的时候,点击输入框,当软键盘弹起来的时候输入框也会被顶上去。如果你不想被顶上去,也可以设置为被软键盘覆盖。
window的其他属性
x与y属性:指定window的位置
alpha:window的透明度
gravity:window在屏幕中的位置,使用的是Gravity类的常量
format:window的像素点格式,值定义在PixelFormat中
三、window相关类
WindowId
WindowId是Window的标识符类,每个Window对象都与一个Window相关联,可以使用WindowId来标识Window对象并处理与之相关的任务。
WindowId代码位于:
frameworks/base/core/java/android/view/WindowId.java
WindowId定义:
public class WindowId implements Parcelable {}
Window
Window类代表了屏幕上的一个矩形区域,即窗口。它是一个抽象类,包括PhoneWindow是它的子类。
Window文件路径:
frameworks/base/core/java/android/view/Window.java
Window定义:
public abstract class Window {
public interface Callback {}
public interface OnWindowDismissedCallback {}
public interface OnWindowSwipeDismissedCallback {}
public interface WindowControllerCallback {}
public interface DecorCallback {}
public interface OnRestrictedCaptionAreaChangedListener {}
public interface OnFrameMetricsAvailableListener {}
public interface OnContentApplyWindowInsetsListener {}
}
Window方法:
public <T extends View> T findViewById(@IdRes int id):在当前窗口中查找指定ID的视图。
public abstract void setContentView(@LayoutRes int layoutResID):设置当前窗口显示的内容视图。
public abstract void setContentView(View view):设置当前窗口显示的内容视图。
public abstract void setContentView(View view, ViewGroup.LayoutParams params):设置当前窗口显示的内容视图。
public abstract void addContentView(View view, ViewGroup.LayoutParams params):将一个视图加到当前布局中已有的视图值上。
public abstract void setTitle(CharSequence title):设置标题。
public void setLayout(int width, int height):设置当前窗口高度和宽度。
public void addFlags(int flags):添加窗口标志位。
public void setFlags(int flags, int mask):设置窗口标志位。
public void clearFlags(int flags):清除窗口标志位。
public WindowManager getWindowManager():获取WindowManager。
public int getColorMode():获取颜色模式。
public abstract LayoutInflater getLayoutInflater():获取Window对象管理的布局填充期。
public void setAttributes(WindowManager.LayoutParams a):设置窗口布局参数。
public void setGravity(int gravity):设置窗口对齐方式。
public void setType(int type):设置窗口类型(优先级)。
public void setFormat(int format) :设置窗口中所有Surface的像素格式。
public void setWindowAnimations(@StyleRes int resId):设置窗口的进入和退出动画效果。
public void setColorMode(@ActivityInfo.ColorMode int colorMode) :设置窗口的色彩模式。
public void setContainer(Window container):设置弹出窗口的容器视图。
public void setUiOptions(int uiOptions):设置窗口的UI表现选项,其中包括多个可选的旋转,可以通过按位或运算将多个选项组合起来,包括SYSTEM_UI_FLAG_FULLSCREEN(全屏模式)、SYSTEM_UI_FLAG_HIDE_NAVIGATION(隐藏导航栏)、SYSTEM_UI_FLAG_IMMERSIVE_STICKY(沉浸式交互特性)。
public void setSoftInputMode(int mode) :设置窗口软键盘交互模式。
public boolean requestFeature(int featureId) :请求窗口显示的特性或功能。
public void setBackgroundDrawableResource(@DrawableRes int resId):设置窗口背景。
public abstract void setFeatureDrawableResource(int featureId, @DrawableRes int resId):设置指定性质的图标资源ID。
public abstract void setFeatureDrawableUri(int featureId, Uri uri):设置指定性质的Uri。
public abstract void setFeatureDrawableUri(int featureId, Uri uri):设置指定性质的图标。
public void setPreferMinimalPostProcessing(boolean isPreferred):开启或关闭最低限度的后期处理。
public abstract void setVolumeControlStream(int streamType):设置音量控制流。
public abstract int getVolumeControlStream():获取音量控制流。
public abstract int getStatusBarColor():获取窗口状态栏颜色。
public abstract void setStatusBarColor(@ColorInt int color):设置窗口状态颜色。
public abstract int getNavigationBarColor():获取窗口导航栏颜色。
public abstract void setNavigationBarColor(@ColorInt int color):设置窗口导航栏颜色
public abstract @NonNull View getDecorView():获取DecorView。
public abstract View peekDecorView():检索当前装饰视图,但前提是该视图已创建。
public abstract void invalidatePanelMenu(int featureId):刷新指定性质的面板菜单。
public abstract boolean isFloating():返回此窗口是否以浮动样式显示。
public abstract boolean isShortcutKey(int keyCode, KeyEvent event):按键是此窗口定义的快捷键之一。
public abstract void takeSurface(SurfaceHolder.Callback2 callback):获取此窗口表面的所有权。
public abstract void takeInputQueue(InputQueue.Callback callback):获取此窗口的 InputQueue 的所有权。
public abstract View getCurrentFocus():返回此窗口中当前具有焦点的视图,如果没有焦点,则返回 null。
public abstract LayoutInflater getLayoutInflater():快速访问此窗口从其上下文中检索到的 {@link LayoutInflater} 实例。
public abstract void openPanel(int featureId, KeyEvent event):
public abstract void closePanel(int featureId);
public abstract void togglePanel(int featureId, KeyEvent event);
public abstract boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags);
public abstract boolean performPanelIdentifierAction(int featureId, int id, int flags);
public abstract void closeAllPanels();
public abstract boolean performContextMenuIdentifierAction(int id, int flags);
public abstract void setFeatureInt(int featureId, int value):Set the integer value for a feature.
public abstract void takeKeyEvents(boolean get):Request that key events come to this activity.
public abstract boolean superDispatchKeyEvent(KeyEvent event):Used by custom windows, such as Dialog, to pass the key press event further down the view hierarchy.
public abstract boolean superDispatchKeyShortcutEvent(KeyEvent event):Used by custom windows, such as Dialog, to pass the key shortcut press event further down the view hierarchy.
public abstract boolean superDispatchTouchEvent(MotionEvent event):Used by custom windows, such as Dialog, to pass the touch screen event further down the view hierarchy.
public abstract boolean superDispatchTrackballEvent(MotionEvent event):Used by custom windows, such as Dialog, to pass the trackball event further down the view hierarchy.
public abstract boolean superDispatchGenericMotionEvent(MotionEvent event):Used by custom windows, such as Dialog, to pass the generic motion event further down the view hierarchy.
public abstract Bundle saveHierarchyState();
public abstract void restoreHierarchyState(Bundle savedInstanceState);
public abstract void setChildDrawable(int featureId, Drawable drawable);
public abstract void setChildInt(int featureId, int value);
public abstract void setDecorCaptionShade(int decorCaptionShade):Set what color should the caption controls be.
public abstract void setResizingCaptionDrawable(Drawable drawable):Set the drawable that is drawn underneath the caption during the resizing.
PhoneWindow
PhoneWindow是系统中提供一个具体实现Window的子类,其主要作用是提供了Android应用程序的界面UI,包括窗口、标题栏、动画效果等,同时还提供了与操作系统交互的支持,例如在系统状态栏提供应用程序的图标和通知,提供电话功能等。
PhoneWindow文件路径:
frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
PhoneWindow定义:
public class PhoneWindow extends Window implements MenuBuilder.Callback {
static class WindowManagerHolder {}
private class PanelMenuPresenterCallback implements MenuPresenter.Callback {}
private final class ActionMenuPresenterCallback implements MenuPresenter.Callback {}
private static final class DrawableFeatureState {}
static final class PanelFeatureState {}
static class RotationWatcher extends Stub {}
public static final class PhoneWindowMenuCallback {}
}
四、Window与其他组件的关系
Window与Surface的关系
如果说Window关心的是层次和布局,是从设计者角度定义的类,Surface则从实现角度出发,是工程师关心和考虑的类。Window的内容是变化 的,Surface需要有空间来记录每个时刻Window的内容。在Android中,通常情况Window与Surface之间的关系是一对一的,在某些情况也会出现一对多的时候,比如,在多个屏幕之前进行切换时,可以使用多个Surface对象,每个Surface对象对应一个屏幕,从而实现多屏显示。此时,一个窗口就包含了多个Surface对象。类似地,在动态生成一些复杂的图形界面时,也可以将一个窗口拆分成多个Surface对象来管理。
Window与Activity的关系
Activity 并不负责视图控制,它只是控制生命周期和处理事件。真正控制视图的是 Window。一个 Activity包含了一个或多个Window,Window才是真正代表一个窗口,Activity就像一个控制器,统筹视图的添加与显示,以及通过其他回调方法,来与 Window、以及 View 进行交互。
下面对Activity和Window对对应情况进行汇总:
1、普通情况:一个Activity对应着一个Window,Activity的UI界面只有一个Window,Window也只对应该Activity的UI界面,Activity与Window是一对一的关系。
2、有子窗口的情况:每个子窗口都是一个单独的View树,每个View树对应一个Window来展示,因此一个Activity会对应多个Window,每个Window都展示了不同的子窗口,Activity与Window是一对多的关系。
3、使用SurfaceView的情况:SurfaceView是一个独立的窗口,它和它所在Activity的其他View不在同一个窗口,因此使用SurfaceView时,Activity与Window也是一对多的关系。
4、使用TextureView的情况:TextureView不是一个独立的窗口,而是一个View,可以与其他View一起组成一个View树,因此在使用TextureView时,Activity与Window也是一对一的关系。
5、多屏幕的情况:每个屏幕都可以由自己的Window,一个Activity可以在多个屏幕中显示,因此在多屏幕的情况,Activity与Window也是一对多的关系。
DecorView 是 FrameLayout 的子类,它可以被认为是 Android 视图树的根节点视图。DecorView 作为顶级 View,一般情况下它内部包含一个竖直方向的 LinearLayout,在这个 LinearLayout 里面有上下三个部分,上面是个 ViewStub,延迟加载的视图(应该是设置ActionBar,根据 Theme 设置),中间的是标题栏(根据Theme设置,有的布局没有),下面的是内容栏。
在 Activity 中通过 setContentView 所设置的布局文件其实就是被加到内容栏之中的,成为其唯一子 View,就是上面的 id 为 content 的 FrameLayout 中,在代码中可以通过 content 来得到对应加载的布局。
一个 Activity 对应一个 Window 也就是 PhoneWindow,一个 PhoneWindow 持有一个 DecorView 的实例,DecorView 本身是一个 FrameLayout。
Activity 与 PhoneWindow 与 DecorView 关系图: