第8章 理解Window和WindowManager

概述

  1. Window是一个抽象类,具体实现是PhoneWindow。
  2. 创建一个Window,通过WindowManger就可以完成。WindowMangager是外界访问Window的入口
  3. Window的具体实现位于WindowMangerService(WMS),WindowManager和WMS的交互是一个IPC过程。
  4. Activity/Dialog/Toast,他们的视图都是附加在Window上的。Window是View的直接管理者。

8.1 Window和WindowManager

  1. 通过WindowManager添加Window的过程
mFloatingButton = new Button(this);
mFloatingButton.setText("test button");
mLayoutParams = new WindowManager.LayoutParams(
        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0,
        PixelFormat.TRANSPARENT);
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);
  1. flags参数解析:

    1. FLAG_NOT_FOCUSABLE:表示window不需要获取焦点,也不需要接收各种输入事件。
    2. FLAG_NOT_TOUCH_MODAL:系统会将window区域外的单击事件传递给底层的window,一般都需要开启这个标记;
    3. FLAG_SHOW_WHEN_LOCKED:开启此模式可以让Window显示在锁屏的界面上。
  2. type参数表示window的类型,window共有三种类型:

    1. 应用window。应用window对应着一个Activity,层级范围是1~99
    2. 子window。子window不能独立存在,需要附属在特定的父window之上,比如Dialog就是子window。层级范围是1000~1999.
    3. 系统window。系统window是需要声明权限才能创建的window,比如Toast和系统状态栏这些都是系统window,需要声明的权限是。层级范围是2000~2999
  3. WindowManager继承自ViewManager,常用的只有三个方法:

    1. addView
    2. updateViewLayout
    3. removeView

8.2 Window的内部机制

  1. Window是一个抽象的概念,每个Window都对应一个View和ViewRootImpl,Window和View通过ViewRootImpl联系,Window是以View的形式存在。
  2. WindowManger是一个接口,真正实现是WindowManagerImpl类,WindowManagerImpl交给WindowMangerGlobal。WindowMangerGlobal以工厂的形式提供自己的实例。
  3. 此处是桥接模式,WindowManagerImple将所有的操作全部委托给WindowManagerGlobal实现。

8.2.1 Window的添加过程

  1. 检查参数是否合法
  2. 创建ViewRootImpl将View添加到列表中
  3. 通过ViewRootImple更新界面并完成Window的添加过程。
    1. 在这里的setViez中会通过requesetLayout完成异步刷新请求。
    2. 会通过WindowSession对WMS进行Binder调用,由WMS实现Window的添加。WMS会对每个应用保留一个单独的Session.

8.2.2 Window的删除过程

  1. 通过findViewLocked查找待删除的View的索引
  2. 调用removeViewLocked删除
  3. 真正删除View的逻辑在dispatchDetachedFromWindow
    1. 垃圾回收
    2. 通过Session的remove删除Window,也是一个IPC过程
    3. onDetachedFromWindow(内部资源回收,比如停止线程、终止动画)
    4. 刷新mViews、mRoots、mDyingViews等数据

8.2.3 Window的更新过程

  1. 更新View的LayoutParams
  2. 更新ViewRootImpl的LayoutParams
  3. 对View重新布局,包括measure、layout、draw三个过程

8.3 Window的创建过程

8.3.1 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真正地完成了添加和显示过程。

8.3.2 Dialog的Window创建过程

  1. 创建Window 。通过PolicyManager的makeNewWindow完成
  2. setContentView,初始化DecorView,并将Dialog视图放到DecorView中
  3. 将DecorView放到Window中显示
  4. 当Dialog关闭,通过WindowManger移除DecorView
  5. 普通Dialog必须才有Activity的Context,应用Token只有Activity拥有。系统window不需要应用Token

8.3.3 Toast的Window创建过程

  1. Toast属于系统Window,它内部的视图由两种方式指定:一种是系统默认的演示;另一种是通过setView方法来指定一个自定义的View。
  2. 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。

你可能感兴趣的:(第8章 理解Window和WindowManager)