美文网首页
Window和WindowManager小结

Window和WindowManager小结

作者: 锋Plus | 来源:发表于2017-11-05 14:30 被阅读33次

    Window是抽象类,具体实现是PhoneWindow,通过WindowManager就可以创建Window。WindowManager是外界访问Window的入口,但是Window的具体实现是在WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC过程。所有的视图例如Activity、Dialog、Toast都是附加在Window上的。

    WindowManager添加View(应用)

    通过WindowManager添加View的过程:将一个Button添加到屏幕坐标为(100,300)的位置上

    private void initView() {
            mCreateWindowButton = (Button) findViewById(R.id.button1);
            mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        }
    
    public void onButtonClick(View v) {
        if (v == mCreateWindowButton) {
            mFloatingButton = new Button(this);
            mFloatingButton.setText("test button");
            mLayoutParams = new WindowManager.LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0,
                    PixelFormat.TRANSPARENT);//0,0 分别是type和flags参数,在后面分别配置了
            mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | LayoutParams.FLAG_NOT_FOCUSABLE
                    | LayoutParams.FLAG_SHOW_WHEN_LOCKED;
            mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR;
            mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
            mLayoutParams.x = 100;
            mLayoutParams.y = 300;
            mFloatingButton.setOnTouchListener(this);
            mWindowManager.addView(mFloatingButton, mLayoutParams);
        }
    }
    
    @Override
    protected void onDestroy() {
        try {
            mWindowManager.removeView(mFloatingButton);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }
    

    其中type如果设置为系统 Window,必须要添加权限:

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    

    不然会报权限不足Error。

    flags参数解析:
    • FLAG_NOT_FOCUSABLE:表示window不需要获取焦点,也不需要接收各种输入事件。此标记会同时启用FLAG_NOT_TOUCH_MODAL,最终事件会直接传递给下层的具有焦点的window;

    • FLAG_NOT_TOUCH_MODAL:在此模式下,系统会将window区域外的单击事件传递给底层的window,当前window区域内的单击事件则自己处理,一般都需要开启这个标记;

    • FLAG_SHOW_WHEN_LOCKED:开启此模式可以让Window显示在锁屏的界面上。

    type参数解析:

    type参数表示window的类型,window共有三种类型:应用window,子window和系统window。

    window是分层的,每个window都对应着z-ordered,层级大的会覆盖在层级小的上面,应用window的层级范围是199,子window的层级范围是10001999,系统window的层级范围是2000~2999。

    这些层级范围对应着 WindowManager.LayoutParams 的 type 参数,如果想要 Window 位于所有 Window 的最顶层,那么采用较大的层级即可,很显然系统 Window 的层级是最大的,当我们采用系统层级时,需要声明权限。

    type的类型有很多,详见:http://blog.csdn.net/panda_xiao/article/details/51657555

    demo运行效果如下:

    5.1版本运行效果.gif

    特别注意:该demo经本人测试,兼容性较差

    该demo在4.4(api19)的虚拟机不能达到系统Window效果(原因有待寻找),笔者虚拟机为5.1(api22)版本,能达到预期效果。
    还有一点要注意,api>=23之后type要是系统窗口(也就是type >= 2000),则需要还一些权限才能使用,至于是什么权限我查了很多网页都没查出来,恐怕是ROOT权限吧

    Window的内部机制

    1. Window是一个抽象的概念,不是实际存在的,它也是以View的形式存在。在实际使用中无法直接访问Window,只能通过WindowManager才能访问Window。每个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系。

    2. Window的添加、删除和更新过程都是IPC过程,以Window的添加为例,WindowManager的实现类对于addView、updateView和removeView方法都是委托给WindowManagerGlobal类,该类保存了很多数据列表,例如所有window对应的view集合mViews、所有window对应的ViewRootImpl的集合mRoots、所有Window 所对应的布局参数的WindowManager.LayoutParams集合mParams、正在被删除的 View 对象的View集合mDyingViews。之后添加操作交给了ViewRootImpl来处理,接着会通过WindowSession来完成Window的添加过程,这个过程是一个IPC调用,因为最终是通过WindowManagerService来完成window的添加的。


      图示总结(来源于网络)

    Window的创建过程

    Activity的window创建过程

    1. Activity的启动过程很复杂,最终会由ActivityThread中的performLaunchActivity来完成整个启动过程,在这个方法内部会通过类加载器创建Activity的实例对象,并调用它的attach方法为其关联运行过程中所依赖的一系列上下文环境变量;
    2. Activity实现了Window的Callback接口,当window接收到外界的状态变化时就会回调Activity的方法,例如onAttachedToWindow、onDetachedFromWindow、dispatchTouchEvent等;
    3. Activity的Window是由PolicyManager来创建的,它的真正实现是Policy类,它会新建一个PhoneWindow对象,Activity的setContentView的实现是由PhoneWindow来实现的;
    4. Activity的顶级View是DecorView,它本质上是一个FrameLayout。如果没有DecorView,那么PhoneWindow会先创建一个DecorView,然后加载具体的布局文件并将view添加到DecorView的mContentParent中,最后就是回调Activity的onContentChanged通知Activity视图已经发生了变化;
    5. 还有一个步骤是让WindowManager能够识别DecorView,在ActivityThread调用handleResumeActivity方法时,首先会调用Activity的onResume方法,然后会调用makeVisible方法,这个方法中DecorView真正地完成了添加和显示过程。
    ViewManager vm = getWindowManager();
    vm.addView(mDecor, getWindow().getAttributes());
    mWindowAdded = true;
    

    Dialog的Window创建过程

    过程与Activity的Window创建过程类似,普通的Dialog的有一个特别之处,即它必须采用Activity的Context,如果采用Application的Context会报错。原因是Application没有应用token,应用token一般是Activity拥有的。

    Toast的Window创建过程

    1. Toast属于系统Window,它内部的视图由两种方式指定:一种是系统默认的演示;另一种是通过setView方法来指定一个自定义的View。
    2. Toast具有定时取消功能,所以系统采用了Handler。Toast的显示和隐藏是IPC过程,都需要NotificationManagerService来实现。在Toast和NMS进行IPC过程时,NMS会跨进程回调Toast中的TN类中的方法,TN类是一个Binder类,运行在Binder线程池中,所以需要通过Handler将其切换到当前发送Toast请求所在的线程,所以Toast无法在没有Looper的线程中弹出。
    3. 对于非系统应用来说,mToastQueue最多能同时存在50个ToastRecord,这样做是为了防止DOS(Denial of Service,拒绝服务)。因为如果某个应用弹出太多的Toast会导致其他应用没有机会弹出Toast。

    总结

    任何 View 都是附属在一个 Window 上面的,Window 表示一个窗口的概念,也是一个抽象的概念,Window 并不是实际存在的,它是以 View 的形式存在的。WindowManager 是外界也就是我们访问 Window 的入口,Window 的具体实现位于 WindowManagerService 中,WindowManagerService 和 WindowManager 的交互是一个 IPC 过程。

    相关文章

      网友评论

          本文标题:Window和WindowManager小结

          本文链接:https://www.haomeiwen.com/subject/gqgcmxtx.html