前言
本文已经收录到我的 GitHub 个人博客, 欢迎大佬们光临寒舍:
我的 GitHub 博客 https://lovelifeeveryday.github.io/
学习清单:
- Windows&WindowManagerService
- Windows&WindowManager
- Windows&PhoneWindow
- Windows&Activity
- Windows&View
Windows 内部机制
Windows 创建过程
一. 为什么要学习 Windows?
Android 手机上所有的视图都是通过 Windows 来呈现的, 像常用的 Activity,Dialog,PopupWindow,Toast, 他们的视图都是附加在 Windows 上的, 所以可以这么说 --「Windows 是 View 的直接管理者」.
Windows 是一个顶层窗口查看和行为的一个抽象基类, 这个类的实例作为一个顶级 View 添加到 Windows Manager. 它提供了一套标准的 UI 方法, 比如添加背景, 标题等等.
Windows 本身很抽象, 深入了解 Windows, 不仅有助于你了解 Android 系统中各个层级之间的关系, 还可以对 Toast 的内部机制, 自定义等等方面会有更加深入的体会.
二. 核心知识点归纳
2.1 Windows 关系解析
看到下面这张大图, 是不是感觉有点乱乱的, 别急, 别急, 心急吃不了热豆腐, 笔者将向您娓娓道来
2.1.1 Windows&PhoneWindow
笔者之前在进阶之路 | 奇妙的 View 之旅中, 提及 setContentView 的时候简单说到了 Windows 和 PhoneWindow, 相信看过的读者已经对此有一个简单的印象.
Windows 是一个抽象类, 它定义了顶级窗体样式和行为. 其唯一的实现类是 PhoneWindow.
2.1.2 Windows&View
笔者之前在进阶之路 | 奇妙的 View 之旅中, 提及 View 工作流程的时候简单说到了 ViewRootImpl, 相信看过的读者已经对此有一个简单的印象.
每个 Windows 都对应一个 View 和一个 ViewRootImpl,Windows 和 View 通过 ViewRootImpl 来建立联系. Windows 并不可见, 它实际以 View 的形式存在, 它是 View 的直接管理者.
- 2.1.3 Windows&
- WindowManagerService
想了解 IPC 的读者, 可以看下笔者写的一篇博客: 进阶之路 | 奇妙的 IPC 之旅 https://juejin.im/post/5e520b5651882549194967c0
Windows 的具体实现位于 WindowManagerService 中. WindowManager 和 WindowManagerService 的交互是一个 IPC(跨进程通信)过程.
2.1.4 Windows&WindowManager
实际使用中无法访问 Windows, 对 Windows 的访问必须通过 WindowManager(换句话说, WindowManager 是外界访问 Windows 的入口), 对 Windows 的操作通过它完成.
例如: 通过 WindowManager 添加 Windows
- // 将一个 Button 添加到屏幕为 (100,300) 的位置
- mFloatingButton = new Button(this);
- mFloatingButton.setText("test button");
- mLayoutParams = new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0,PixelFormat.TRANSPARENT);// 第三个参数代表 flags, 第四个参数代表 type
- mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
- | LayoutParams.FLAG_NOT_FOCUSABLE
- | LayoutParams.FLAG_SHOW_WHEN_LOCKED;// 配置 flags
- mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR;// 配置 type
- mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;// 配置 gravity
- mLayoutParams.x = 100;// 相对于 gravity
- mLayoutParams.y = 300;// 相对于 gravity
- mFloatingButton.setOnTouchListener(this);
- mWindowManager.addView(mFloatingButton, mLayoutParams);
下面依次介绍 WindowManager 的三个重要参数:
flags: 表示 Windows 的属性. 主要的可选值含义:
FLAG_NOT_FOCUSABLE: 表示 Windows 不需要获取焦点, 也不需要接收各种输入事件, 此标记会同时启动
FLAG_NOT_TOUCH_MODEL
, 最终事件会传递给下层的具有焦点的 Windows.
FLAG_NOT_TOUCH_MODAL
: 表示系统会将当前 Windows 区域以外的单击事件传递给底层的 Windows, 而区域以内的单击事件则自己处理. 一般都需要开启此标记, 否则其他 Windows 将无法收到单击事件.
FLAG_SHOW_WHEN_LOCKED
: 表示 Windows 可显示在锁屏界面.
type: 表示 Windows 的类型. Windows 有三种类型:
A. 应用类 Windows: 对应一个 Activity
B. 子 Windows: 不能单独存在, 需附属特定的父 Windows. 如 Dialog
C. 系统 Windows: 需声明权限才能创建. 如 Toast
系统权限有很多值, 一般选用: TYPE_SYSTEM_OVERLAY/TYPE_SYSTEM_ERROR
记得声明权限:<uses-permission Android:name="android.permission.SYSTEM_ALERT_WINDOW"/>,Android6.0 以下直接声明权限即可, Android6.0 以上还需要用户打开软件设置页手动打开, 才能授权.
Windows 是分层的, 见下表
层级大的会覆盖在层级小的 Windows 上面.
对应 WindowManager.LayoutParams 的 type 参数.
Window | 层级 |
---|---|
应用 Window | 1-99 |
子 Window | 1000-1999 |
系统 Window | 2000-2999 |
gravity: 表示 Windows 的位置.
默认是屏幕中间
x,y 值相对于 gravity
2.2 Windows 的内部机制
WindowManager 对 Windows 主要有三大操作: 添加, 更新和删除.
这三个方法主要是定义在 ViewManager 接口中:
- public interface ViewManager
- {
- public void addView(View view, ViewGroup.LayoutParams params);// 添加过程
- public void updateViewLayout(View view, ViewGroup.LayoutParams params);// 更新过程
- public void removeView(View view);// 删除过程
- }
WindowManager 也是一个接口, 它继承了 ViewManager 接口:
public interface WindowManager extends ViewManager {}
WindowManager 的具体实现类是 WindowManagerImpl:
- public final class WindowManagerImpl implements WindowManager{
- @Override
- public void addView(View view, ViewGroup.LayoutParams params){
- mGlobal.addView(view, params, mDisplay, mParentWindow);
- }
- @Override
- public void updateViewLayout(View view, ViewGroup.LayoutParams params){
- mGlobal.updateViewLayout(view, params);
- }
- @Override
- public void removeView(View view){
- mGlobal.removeView(view, false);
- }
- }
由以上代码可见, WindowManagerImpl 并没有直接实现 Windows 的三大操作, 而是交给了
- WindowManagerGlobal
- .
- WindowManagerGlobal
以单例模式向外提供自己的实例:
WindowManagerImpl 这种工作模式是典型的桥接模式 https://www.jianshu.com/p/5bb60f943827
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
一幅图说明这几个类的关系:
因此, 通过 WindowManagerGlobal 的 addView(),updateViewLayout(),removeView()实现 WindowManager 对 Windows 的添加, 删除和修改.
2.2.1 Windows 的添加
2.2.2 Windows 的删除
2.2.3 Windows 的更新
不难发现, 以上验证了之前的总结:
Windows 的三大操作最终都会通过一个 IPC https://juejin.im/post/5e520b5651882549194967c0 过程移交给
- WindowManagerService
- .
Windows 和 View 通过 ViewRootImpl 来联系, ViewRootImpl 可控制 View 的测量, 布局和重绘.
限于篇幅, 笔者这里暂未贴上源码, 如果想了解的话, 推荐一篇文章: 我眼中的 Windows 创建 / 添加 / 删除 / 更新过程
2.3 Windows 的创建过程
由于 View 必须依附 Windows 才能呈现出来, 因此有 View 的地方必有 Windows. 在 Android 中可以提供 View 的地方有 Activity,Dialog 和 Toast,PopupWindow, 菜单, 下面分别来看 Activity,Dialog 和 Toast 三种 Windows 的大致创建过程:
2.3.1 Activity 的 Windows 创建过程
Activity 的启动流程这里不了解没关系, 笔者后面会专门写一篇文章来介绍
想了解 Activity 的 Windows 创建过程的源码的读者, 笔者推荐一篇文章: Activity 的 Windows 创建过程分析
2.3.2 Dialog 的 Windows 创建过程
Dialog.show()方法: 完成 DecorView 的显示
WindowManager.remoteViewImmediate()
方法: 当 Dialog 被 dismiss 时移除 DecorView
2.3.3 Toast 的 Windows 创建过程
Q1:Toast 的内部的视图由两种方式指定:
系统默认的样式
通过 setView()指定一个自定义 View
Q2:Toast 具有定时取消功能, 故系统采用 Handler 做定时处理
Q3: 在 Toast 内部有两类 IPC https://juejin.im/post/5e520b5651882549194967c0 过程:
Toast 访问
- NotificationManagerService()
- (
- NotificationManagerService
运行在系统的进程);
NotificationManagerService
回调 Toast 里的 TN 接口(运行在 Binder 线程池).
Q4:Toast 提供方法 show()和 cancel()分别用于显示和隐藏 Toast.
Toast 的显示和隐藏都需要通过 NMS 来实现, 由于 NMS 运行在系统进程中, 故需通过远程调用的方式来进行显示和隐藏 Toast.
NMS 处理 Toast 的显示和隐藏请求时会跨进程回调 TN 中的方法, 但是由于 TN 运行在 Binder 线程池中, 故需通过 Handler 将其切换到当前线程(发送 Toast 请求的线程).
NMS 只是起到了管理 Toast 队列及其延时的效果
Toast 的显示和隐藏实际是通过 TN 来实现的.
想了解 Toast 的 Windows 创建过程的源码的读者, 笔者推荐一篇文章: Android 对话框 Dialog,PopupWindow,Toast 的实现机制
三. 课堂小测试
恭喜你! 已经看完了前面的文章, 相信你对 Windows 已经有一定深度的了解, 下面, 进行一下课堂小测试, 验证一下自己的学习成果吧!
Q1: 一个应用中有多少个 Windows?
答案: 无限个. 原因: 任何一个 View 都是依附在 Windows 上面, 一个应用可以有无限个 View, 自然 Windows 也是无限个.
Q2:Windows 对象有存在的必要吗?
疑惑点: Windows 能做的事情, View 对象基本都能做: 像触摸事件, 管理各个子 View 等等.
可能有人会说:"Window 是 View 的管理者".
追问: 我们知道, WindowManager 是 Windows 的管理者, 那为什么不直接用 WindowManager 管理 View 呢?
答案: 站在系统的角度上看, 系统是 "不知道" 有 View 对象这个说法的! 作为系统, 我有自己的骄傲, 不去管你 Windows 如何搬砖, 如何砌墙, 只给你地皮. 而这时, Windows 为了绘制出用户想要的组件(按钮, 文字, 输入框等等), 系统又不给我! 没事, 那我自己定义, 于是就定义了 View 机制, 给每个 View 提供 Canvas, 让不同的 View 自己绘制具有自己特色的组件. 同时, 为了更好的管理 View, 通过定义 ViewGroup, 等等.
Q3:Activity 有存在的必要吗?
疑惑点: Windows 已经是系统管理的窗口界面. 那么为什么还需要 Activity 呢? 我们把 Activity 所做的事情, 全部封装到 Windows 不就好了? 悬浮窗口 Dialog 中不就是没有使用 Activity 来显示一个悬浮窗吗?
答案: Android 中的应用中, 里面对各个窗口的管理相当复杂(任务栈, 状态等等). 但是如果让用户自己去管理这些 Windows, 先不说工作量, 光让用户自己去实现任务栈这点, 就很难了. 为了让大家能简单, 快速的开发应用, Android 让 Activity 帮我们管理好, 我们只需简单的去重写几个回调函数, 无需直接与 Windows 对象接触.
任何事物都有规律, 语言再难, 也是人发明的, 一样具有社会性, 其实这几个的关系就像是国家的中央系统的官员分配一样, 从古至今, 一层对一层负责, 这样各司其职, 又相互一层层联系着, 达到效率最大化, 突然发现, 古人的智慧还是很厉害的, 你让皇帝 (系统) 去管辖所有的官员(view), 岂不是要累死? 所以才出现了中间这些 "官员"
如果文章对您有一点帮助的话, 希望您能点一下赞, 您的点赞, 是我前进的动力
本文参考链接:
《Android 开发艺术探索》
桥接模式 https://www.jianshu.com/p/5bb60f943827
我眼中的 Windows 创建 / 添加 / 删除 / 更新过程
Activity 的 Windows 创建过程分析
Android 对话框 Dialog,PopupWindow,Toast 的实现机制
学习笔记 | AS 入门(番外) 技能篇 https://www.jianshu.com/p/c9496c8bed4c
要点提炼 | 开发艺术之 Windows https://www.jianshu.com/p/ed03aed9a4db
Android Windows 机制探索
理清 Activity,View 及 Windows 之间关系
Android 6.0 之后 Android.permission.SYSTEM_ALERT_WINDOW 使用方法变动
一个 App 有多少个 Windows? https://segmentfault.com/q/1010000011842138
来源: https://www.cnblogs.com/xcynice/p/qi_miao_de_window_zhi_lv.html