第八章、理解Window和WindowManager

> Window表示一个窗口的概念。Window是一个抽象类,它的具体表现是PhoneWindow。通过WindowManager即可创建一个Window。Window的具体实现位于WindowManagerService中,WindowManager和WindowManagerServide的交互是一个IPC的过程。Android的中所有的视图都是通过Window呈现的,Window实际上是View的直接管理者。
  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);//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);
    2. Window常用的几个Flags属性
      1. FLAG_NOT_FOCUSABLE:
        表示Window不需要获取焦点,也不需要接收各种输入事件。此标记会同时启用FLAG_NOT_TOUCH_MODAL,最终事件会直接传递给下层的具有焦点的Window。
      2. FLAG_NOT_TOUCH_MODAL:
        在此模式下,系统会将window区域外的单击事件传递给底层的window,当前window区域内的单击事件则自己处理,一般都需要开启这个标记
      3. FLAG_SHOW_WHEN_LOCKED:
        开启此模式可以让Window显示在锁屏的界面上。
    3. Type参数表示Window的类型,有三种类型:
      1. 应用Window:
        对应着一个Activity
      2. 子Window:
        子View不能单独存在,需要依附在特定的富Window之中,比如常见的Dialog
      3. 系统Window:
        系统Window是需要申明权限才能创建Window。比如Toast和系统状态栏都是系统Window。
    4. Window是分层的,层级大的会覆盖在层级小的Window的上面。

      1. 应用Window的层级范围:1-99
      2. 子Window的层级范围:1000-1999
      3. 系统Window的层级范围:2000-2999
    5. WindowManager提供的有三个常用的方法:

      1. 添加View
      2. 更新View
      3. 删除View
  2. Window的内部机制

    1. Window是一个抽象概念,Window并不是实际存在的,它是以View的形式存在的。View才是Window存在的实体。
    2. Window的添加过程需要通过WindowManager的addView来实现。它的真正实现是WindowManagerImpl类,WindowManagerImpl并没有直接实现window的三大操作,而是全部交给了WindowManagerClobal来处理。。这种事典型的桥接模式。
    3. WindowManagerGlobal的addView过程:

      1. 检查参数是否合法,如果是子Window那么还需要调整一些布局参数。
      2. 创建ViewRootImpl并将View添加到列表中
      3. 通过ViewRootImpl来更新界面并完成Window的添加过程。
    4. * WindowManagerGlobal的removeView过程:*

      1. 首先通过findViewLocked来查找待删除的View的索引,查找的过程就是遍历数组,然后再通过removeViewLocked来做进一步的删除。
      2. removeLocked是通过ViewRootImpl来完成删除的。两种删除接口,removeView和removeViewImmediate。分别代表异步删除和同步删除。一般不使用同步删除。
      3. removeLocked里面会调用die方法,如果是异步删除,将其添加到待删除列表中,同时发送一个MSG_DIE的消息,ViewRootImpl中的Handler会处理此消息并调用doDie方法 。如果是同步删除,不发送消息,直接调用doDie方法。doDie最后调用了dispatchDetachedFromWindow方法。
      4. dispatchDetachedFromWindow主要流程:
        1. 垃圾回收
        2. 通过Session的remove方法删除Window,最终调用WindowManagerService的removeWindow方法
        3. 调用View的dispatchDetachedFromWindow方法。当View从Window中移除时,会调用onDetachedFromWindow()方法,这个方法内部可以做一些资源回收工作。
        4. 调用windowManagerGlobal的doRemoveView方法刷新数据。
    5. WindowManagerGlobal的更新过程
      1. 更新View的LayoutParams并将老的LayoutParams替换掉。
      2. 更新ViewRootImpl中的LayoutParams。通过setLayoutParams来完成的。
      3. 通过scheduleTraversals来对View重新布局,包括测量,布局,重绘三个过程。
  3. Window的创建过程

    View 是Android中的视图呈现方式,有视图的地方就有Window。

    1. Acitivity的Window创建过程:

      1. 在ActivityThread中的performLanunchActivity()来完成整个启动过程,方法内部会创建Activity实例对象,并通过attach方法为其关联运行中所需要的环境变量。
      2. attach方法里,系统会创建Activity所属的Window对象,并为其设置回调接口。由于Activity实现了Window的回回调接口,所有当Window接收到外界状态改变时,就会回调Activity的方法。
      3. Activity将具体实现交给了Window,Window的具体处理是PhoneWindow,所以只需要看PhoneWindow相关逻辑即可。PhoneWindow的setContentView方法大致如下几个步骤:
        1. 没有DecorView,就创建它。
        2. 将View添加到DecorView的mContentParent中
        3. 回调Activity的onContentChanged方法通知Activity视图已经发生了变化。
        4. 此时DecorView并没有被WindowManager识别,所以这个时候的Window无法提供具体功能。在ActivityThread的handleResumeActivity方法中,首先会调用Activity的onResume方法,接着会调用Activity的makeVisible(),在makeVisiable中,DecorView真正完成了添加和显示两个过程,此时Activity的视图才能被用户看到。
    2. Dialog的window创建过程

      1. 创建Window
      2. 初始化DecorView并将Dialog的视图添加到DecorView中
      3. 将DecorView添加到window并显示。

      普通Dialog有一个特殊之处,那就是必须采用Activity的Context,如果采用Application的Context,那么就会报错。
      报错的信息就是没有应用token所致的。token一般只有Activity拥有,所以只需要用Activity作为Context来显示对话框即可。但是系统Window比较特殊,不需要token。所以只需要指定对话框的Window为系统类型就可正常弹出对话框。
      dialog.getWindow().setType(LayoutParams.TYPE_SYSTEM_ERROR)
      最后在AndroidManifest文件中声明权限就可以了。

    3. Toast创建过程

      1. Toast由于具有定时取消的功能,所以系统采用了Handler在Toast内部有两类IPC,第一类是Toast访问NotificationManagerService (NMS),第二类是NotificationManagerService会调Toast里的TN接口。
      2. Toast属于系统Window,内部视图有两种方式指定。系统默认和通过setView方法来指定一个View。
      3. Toast提供了show和cancel分别用于显示和隐藏Toast。它们的内部是一个IPC过程。
      4. Toast显示和隐藏都是通过NMS来实现,NMS运行在系统进程中。NMS处理Toast请求时会跨进程调用TN中的方法。TN运行在Binder线程池中,所以通过Handler切换到当前线程。Handler需要使用Looper才能完成线程切换。
      5. 对于非系统应用来说,mToastQueue最多能同时存在50个ToastRecord,这样做是为了防止DOS(Denial of Service,拒绝服务)。因为如果某个应用弹出太多的Toast会导致其他应用没有机会弹出Toast。

更多相关文章

  1. Android文本输入框EditText方法说明和属性
  2. Android中OptionMenu用法实例
  3. AndroidStudio3.2 Failed to resolve:.......问题解决方法
  4. Android使用criteria选择合适的地理位置服务实现方法
  5. android 升级webview的方法
  6. Android加载缩略图的几种方法
  7. android在ubuntu桌面系统下编译可能的错误和解决方法
  8. Android(安卓)异步开发之 AsyncQueryHandler
  9. android中对程序进行数字证书签名的方法

随机推荐

  1. Android(安卓)封装http请求的工具类
  2. Android通过TCPIP协议实现断点续传上传实
  3. Android简单实现猜拳游戏
  4. Android(安卓)SDK Tutorial: Button onCl
  5. Android开机自启
  6. Android: PLEASE DO NOT USE A WAKE LOCK
  7. android 前后台切换 回调
  8. ktolin在Android中布局界面拼接
  9. Android(安卓)播放音乐文件与视频文件
  10. Android(安卓)gallery详解