第八章 理解 Window 和 WindowManager

在桌面上需要展示一个类似悬浮窗的东西,需要使用到 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 的添加过程

这里写图片描述

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

8.2.2 Window 的删除过程

这里写图片描述

8.2.3 Window 的更新过程

这里写图片描述

8.3 Window 的创建过程

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

8.3.1 Acticity 的 Window 创建过程

创建Window:
这里写图片描述
setContentView():
这里写图片描述

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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值