Android开发艺术探索——理解Window和WindowManager

这是我在学习过程中总结的知识
目的是希望日后回来看或者需要用的时候可以 一目了然 # 的回顾、巩固、查缺补漏
不追求详细相当于书本的精简版或者说是导读(想看详细的直接对应翻书),但会尽力保证读者都能快速理解和快速使用(随理解加深会总结的更加精简),但必要时会附上一些较详细解释的链接
脚注是空白的:表示还没弄懂的知识,了解后会添加

  • 常用Window来实现悬浮窗,它还是View的直接管理者
  • Window是抽象类,具体实现为PhoneWindow
  • WindowManager 是外界访问Window的入口
  • WindowManagerService 是Window的具体实现
  • WindowManager和WindowManagerService交互是一个IPC过程
  • Android所有视图都是附在Window上的(Activity、Toast等)

8.1 Window和WindowManager

先通过代码演示通过WindowManager添加Window的过程
总体分两部分看,一是生成一个View(Button),然后设置View的参数(LayoutParams)

            mFloatingButton = new Button(this);
            mFloatingButton.setText("click me");
            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);

然后LayoutParams中的flags和type是比较重要的参数,下面介绍一些常用的

FLAG_NOT_FOCUSABLE
表示Window不需要获取焦点,然后同时启动FLAG_NOT_TOUCH_MODAL,事件还会传递给下层具有焦点的Window

FLAG_NOT_TOUCH_MODAL
简单来说,悬浮窗内的点击事件自己处理,而不接收悬浮窗外的点击事件

FLAG_SHOW_WHEN_LOCKED
将Window显示在锁屏界面上

Type参数表示Window的类型

  • 应用Window(1~99):需要和Activity一起
  • 子Window(1000~1999):不能单独,需要附属在父Window中,如Dialog
  • 系统Window(2000~2999):需要先声明权限才能创建,如Toast和系统状态栏

Window是分层的,每个Window都有对应的z-ordered(如上的数字)
层级大的会覆盖层级小的Window上面
使用系统Window需要声明权限 uses-permission android:name=“android.permission.SYSTEM_ALERT_WINDOW”
WindowManager常用的3个功能,添加、更新、删除View(方法继承于ViewManager接口)

8.2 Window的内部机制

Window是一个抽象的概念,每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,因此Window并不是实际存在的而是以View的形式存在

从WindowManager的定义也可以看出,它的操作都是针对View的,要访问Window必须通过WindowManager

8.2.1 Window 的添加过程

WindowManager是一个接口,真正实现是 WindowManagerImpl 继承的addView方法

查看源码可知,WindowManagerImpl将操作又交给了 WindowManagerGlobal 来处理,这是一种桥接的工作模式
现在来看WindowManagerGlobal的addView 方法
1.检查参数合法性,可能调整子Window参数
2.创建一个ViewRootImpl然后将之前所有的View、新的ViewRootImpl、之前所有的布局参数添加到对应的list中
3. 通过ViewRootImpl来更新界面并完成Window的添加过程

8.2.2 Window的删除过程

8.2.3Window的更新过程

8.3 Window的创建过程

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

8.3.1 Activity的Window创建过程

· 在Activity的attach方法里,系统会创建Activity所属的Window对象并为其设置回调接口
· Window对象的创建时通过PolicyManager的makeNewWindow方法实现的
· 由于Activity实现了Window的Callback接口,所有当Window接收到外界状态改变时就会回调Activity的方法

PolicyManager
Activity的Window是通过PolicyManager的一个工厂方法来创建的,这些方法全部在策略接口IPolicy中声明了

Policy类
PolicyManager的真正实现是Policy类,关键的 makeNewWindow 方法在Policy内

PhoneWindow
makeNewWindow将Window的具体实现推给PhoneWindow

PhoneWindow的setContentView

  1. 如果没有DecorView就创建它

DecorView是一个FrameLayout、是Activity的顶级View

创建它的方法由installDecor——generateDecor完成
再通过generateLayout初始化DecorView的结构加载布局文件

  1. 将View添加到DecorView的mContentParent中
    这一步直接将Activity的视图添加到DecorView的mContentParent中即可,然后Activity的布局文件已经添加到DecorView里面了

  2. 回调Activity的 onContentChanged 方法通知Activity视图已经发生改变
    之前说的Activity实现了Window的Callback接口,所以现在要通知Activity作出相应的处理(onContentChanged)

最后还需要让WindowManager识别DecorView,再通过Manager添加到Window才能实现接收外界信息输入的功能

8.3.2 Dialog的Window过程

1. 创建Window
和Activity类似,也是通过PolicyManager的makeNewWindow方法来完成的,创建后的对象是PhoneWindow

2. 初始化DecorView并将Dialog的视图添加到DecorView中
也和Activity类似,都是通过Window去添加指定的布局文件

3. 将DecorView添加到Window中并显示
在Dialog的show 方法中,会通过WindowManager将DecorView添加到Window中,也类似··

普通的Dialog必须采用Activity的Context不能是Application的Context

8.3.3 Toast的Window创建过程

  • Toast采用了Handler来实现定时取消
  • 视图有两种:一是默认样式、二是通过setView指定一个自定义View.它们都对应Toast的一个View类型的内部成员(mNextView)

显示和隐藏Toast都需要NMS(NotificationManagerService)来实现,由于NMS运行在系统进程,所以需要用到TN这个类(Binder类).
即:Toast和NMS进行IPC过程中,NMS处理Toast的请求会跨进程回调TN中的方法

Toast的显示过程

  1. 调用了NMS的enqueueToast方法
  2. enqueueToast将Toast请求封装为ToastRecord对象并添加到一个名为mToastQueue的队列中(ArrayList)
  3. 显示时由ToastRecord的callback(TN对象的远程Binder)来完成的
  4. Toast显示以后,NMS通过scheduleTimeoutLocked方法来发送一个延时消息
  5. 延时结束后,MNS通过cancelToastLocked方法来隐藏Toast并将其从mToastQueue中移除

由第三点可知,Toast真正的显示隐藏方法是由TN完成的
即TN中的handleShow和handleHide

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值