欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

第八章 理解 Window 和 WindowManager

程序员文章站 2022-05-26 08:41:13
...

在桌面上需要展示一个类似悬浮窗的东西,需要使用到 Window 来实现。
Window 是一个抽象类,具体实现是 PhoneWindow。WindowManger 是外界访问 Window 的入口,Window的具体实现位于 WindowMangerService 中,WindowManager 和 WindowMangerService的交互是一个 IPC 过程。
Android 中的所有视图都是通过 Window 来呈现的,Activity、Dialog 和 Toast 的视图都是附加在 Window 上,因此,Window 也是 View 的直接管理者。
View 的事件分发机制:单击事件由 Window 传递给 DectorView,然后再由 DecorView 传递给我们的 View。连Activity 设置视图的方法 setContentView() 在底层也是通过 Window 完成。

8.1 Window 和 WindowManager

使用 WindowManager 添加一个 Window:

        /**
         * 当手机是锁屏状态的时候,此时运行代码,则会展现在锁屏界面上,可返回到锁屏界面
         * 锁屏时点击不会弹出Toast,但是会走onClick方法。
         */
        final Button button = new Button(getApplicationContext());
        button.setText("text");
        final WindowManager.LayoutParams layoutParams
                = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSPARENT);

        layoutParams.flags = WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
        ;
        layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION;
        /**
         * 不设置gravity或者设置为CENTER,则下面的x,y设置无效
         */
        layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
        /**
         * layoutParams.x/y:是组件的左上角坐标
         * event.getRawX/Y:是手指相对于屏幕的左上角的距离
         * layoutParams.y:不包括通知栏的高度,y = event.getRawX - event.getX - 通知栏的高度
         */
        layoutParams.x = 0;
        layoutParams.y = 0;
        final WindowManager windowManager = getWindowManager();
        windowManager.addView(button, layoutParams);

Flags:表示 Window 的属性。
FLAG_SHOW_WHEN_LOCKED:开启此模式可以让 Window 出现在锁屏上。
FLAG_SHOW_NOT_FOCUSABLE:表示Window不需要获取焦点,也不需要接收各种输入事件,此标记会启用FLAG_NOT_TOUCH_MODAL,最终事件会传递给下层的具有焦点的Window。
FLAG_NOT_TOUCH_MODAL:系统会将当前 Window 区域以外的单击事件传递给底层的Window,当前的Window区域以内的单击事件则自己处理。一般都需要开启此标记,否则其他 Window 无法收到单击事件
Type:表示 Window 的类型,Window 有三种类型,应用 Window、子 Window 和系统 Window,Window 是分层的,每隔 Window 都有对应的 z-ordered,层级打的会覆盖层级小的 Window的上面。
应用类 Window:对应一个 Activity,层级范围是 1 ~ 99。
子 Window:不能单独存在,需要附属在特定的父 Window 之中,比如常见的 Dialog;层级范围是1000 ~ 1999
系统 Window:需要声明权限在能创建的 Window,比如 Toast 和系统状态栏;层级范围是2000 ~ 2999。
WindowManager 继承 ViewManager,常用方法:添加 View(addView),更新 View(updateViewLayout),删除 View(removeView).这三个方法定义在 ViewManager 中。
WindowManager 操作 Window 的过程更像是在操作 Window 中的 View。

8.2 Window 的内部机制

每一个 Window 都对应着一个 View 和一个 ViewRootImpl,Window 和 View 通过 ViewRootImpl 来建立联系。实际使用中无法直接访问 Window,对 Window 的访问必须通过 WindowManager。

8.2.1 Window 的添加过程

第八章 理解 Window 和 WindowManager

Session的个人理解:
WindowManagerGlobal中新建一个 ViewRootImpl 对象,而 ViewRootImpl 会调用WindowManagerGlobal.getWindowSession(),在该方法中首先会获取WMS对象,通过调用windowManager.openSession获取 Session 对象,之后WindowManagerGlobal便通过 ViewRootImpl 调用 Session 的 add、remove 方法,在 add、remove 方法中会调用 WMS 的 addWindow、removeWindow

8.2.2 Window 的删除过程

第八章 理解 Window 和 WindowManager

8.2.3 Window 的更新过程

第八章 理解 Window 和 WindowManager

8.3 Window 的创建过程

View 必须附着在 Window 的上面,有视图的地方就有Window,因此,Activity、Dialog、Toast等视图都对应着一个Window。

8.3.1 Acticity 的 Window 创建过程

创建Window:
第八章 理解 Window 和 WindowManager
setContentView():
第八章 理解 Window 和 WindowManager

8.3.2 Dialog 的 Window 创建过程

   new Dialog(this).setContentView(view/resourceId)show();

1. 创建 Window
和Activity非常类似

    Dialog(Context context, int theme, boolean createContextThemeWrapper) {
        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        /**
         * Window的创建也是通过PolicyManager.makeNewWindow来完成,创建后的对象实际上就是PhoneWindow。
         */
        Window w = PolicyManager.makeNewWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);
    }

2. 初始化DecorView并将Dialog的视图添加到DecorView中
通过window添加指定的文件。

    public void setContentView(int layoutResID) {
        mWindow.setContentView(layoutResID);
    }

3. 将DecorView添加到Window中显示

    public void show() {
          /**
           * 通过WindowManager将DecorView添加到Window中
           */
          mWindowManager.addView(mDecor, l);
    }
  1. 当 Dialog 被关闭时,会通过 WindowManager 来移除DecorView:
      /**
       * 移除DecorView
       */
       mWindowManager.removeViewImmediate(mDecor);
相关标签: 第八章