内容简介:Window 是一个抽象类,它的具体实现是 PhoneWindow。可以通过 WindowManager 创建 Window。Android 中所有视图都是附加在 Window 上的,因此 Window 实际上是 View 的直接管理者。先看一段示例代码:上面的代码简单的实现了一个悬浮窗的功能,里面涉及到了以下知识点:
Window 是一个抽象类,它的具体实现是 PhoneWindow。可以通过 WindowManager 创建 Window。Android 中所有视图都是附加在 Window 上的,因此 Window 实际上是 View 的直接管理者。
Window 和 WindowManager
先看一段示例代码:
WindowManager wmManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams(); wmParams.type = LayoutParams.TYPE_PHONE; wmParams.format = PixelFormat.RGBA_8888; wmParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE; wmParams.gravity = Gravity.RIGHT | Gravity. CENTER_VERTICAL; wmParams.x = 0; wmParams.y = 0; wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT; wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT; wmManager.addView(view,wmParams);
上面的代码简单的实现了一个悬浮窗的功能,里面涉及到了以下知识点:
-
Flags 常用选项:
- FLAG_NOT_FOCUSABLE : 表示 Window 不需要获取焦点,也不需要接收各种输入事件,此标记会同时启用 FLAG_NOT_TOUCH_MODAL,最终事件会往下传递。
- FLAG_NOT_TOUCH_MODAL :表示会将当前 Window 区域以外的点击事件传递给底层的 Window,自己区域内的当然由自己来处理,一般来说,都要开启本标记。
- FLAG_SHOW_WHEN_LOCKED :表示可以让 Window 显示在锁屏界面上。
-
Types 参数:
Types 参数表示 Window 的类型,有三种: 应用 Window 、 子 Window 和 系统 Window 。
- 应用 Window :对应着一个 Activity
- 子 Window :不能单独存在,它需要附属在特定的父 Window 上,例如 Dialog
- 系统 Window :需要申明权限才能创建,例如 Toast 和状态栏
-
Window 是分层的,每个 Window 都有对应的
z-ordered
,层级大的会覆盖在层级小的上面。这些层级范围对应着上面的 Types 参数。- 应用 Window 层级范围:1~99
- 子 Window 层级范围:1000~1999
- 系统 Window 层级范围:2000~2999
-
创建系统类型的 Window 时需要声明权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
,不然会报错。 - WindowManager 提供的功能很简单,常用的就三个: 添加 View 、 更新 View 和 删除 View 。
-
如果我们要实现悬浮窗的拖动只要在
onTouch
方法中不断更新 View 的位置即可。
Window 的内部机制
Window 是一个抽象的概念,每一个 Window 都对应着一个 View 和一个 ViewRootImpl,Window 和 View 通过 ViewRootImpl 来建立联系,因此 Window 并不实际存在,它以 View 的形式存在,这就是为什么实际使用中无法直接访问 Window,而都是通过 WindowManager 来进行的。
Window 的添加过程
Window 的添加过程需要通过 WindowManager 的 addView
来实现。WindowManager 是一个接口,它的真正实现是 WindowManagerImpl 类,翻看源码发现 WindowManagerImpl 也没有直接实现 Window 的三大操作,而是委托给了 WindowManagerGlobal 来实现。
WindowManagerGlobal 的 addView
方法主要分为几步:
- 检查参数是否合法,如果是子 Window 那么还需要调整一些布局参数
- 创建 ViewRootImpl 并将 View 添加到列表中
- 通过 ViewRootImpl 来更新界面并完成 Window 的添加过程
最终会通过 IPC 调用 WindowManagerService 去处理。
Window 的删除过程
WindowManager 提供两种删除接口: removeView
和 removeViewImmediate
,我们一般使用前者,后者可能会出现一些意外的错误。
真正删除 View 的逻辑在 dispatchDetachedFromWindow
方法内部实现,主要做四件事:
- 垃圾回收相关的工作
-
通过 Session 的
remove
方法删除 Window,同样是一个 IPC 过程,最终调用 WindowManagerService 的removeWindow
方法 -
调用 View 的
dispatchDetachedFromWindow
方法 -
调用 WindowManagerGlobal 的
doRemoveView
方法刷新数据。
Window 的更新过程
Window 的更新主要是通过 WindowManagerGlobal 的 updateViewLayout
方法,首先更新 View 的 LayoutParams,接着更新 ViewRootImpl 中的 LayoutParams,在 ViewRootImpl 中会通过 scheduleTraversals
方法来对 View 进行重新布局,此外还会通过 WindowSession 来更新 Window 的视图,最终由 WindowManagerService 的 relayoutWindow
来实现。
Window 的创建过程
Activity 的 Window 创建过程
Activity 所属的 Window 对象通过 PolicyManager 的 makeNewWindow 方法实现。Window 的具体实现是 PhoneWindow。Activity 通过 setContentView 方法把具体实现交给了 PhoneWindow 去处理。
PhoneWindow 的 setContentView
大致有以下几个步骤:
-
如果没有 DecorView,那么创建它
DecorView 是一个 FrameLayout,是 Activity 中的顶级 View,它包含标题栏和内容栏,其实内容栏的完整 id 是 android.R.id.content。
-
将 View 添加到 DecorView 的 mContentParent 中
- 回调 Activity 的 onContentChanged 方法通知 Activity 的视图已经发生改变
最后在 ActivityThead 的 handleResumeActivity 方法中调用 Activity 的 onResume 方法,接着会调用 Activity 的 makeVisible 方法,最终才能显示出来。
Dialog 的 Window 创建过程
Dialog 的 Window 创建过程与 Activity 类似,具体有以下几个步骤:
- 创建 Window
- 初始化 DecorView 并将 Dialog 的视图添加到 DecorView 中
- 将 DecorView 添加到 Window 中并显示
值得注意的是,普通 Dialog 必须采用 Activity 的 Context,如果是 Application 的则会报错,这是因为没有 token 所导致的,一般只有 Activity 才拥有。
此外,系统 Window 是不需要 token 的,但是需要声明权限。
Toast 的 Window 创建过程
Toast 属于系统 Window,它的内部视图由两种方式指定:一是系统默认样式,二是通过 setView
方法来指定一个自定义 View。Toast 的内部有两类 IPC 过程,第一类是 Toast 访问 NotificationManagerService,第二类是 NotificationManagerService 回调 Toast 里的 TN 接口,最终实现 Toast 的显示和隐藏。
以上所述就是小编给大家介绍的《理解 Window 和 WindowManager》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 理解原型其实是理解原型链
- 要理解深度学习,必须突破常规视角去理解优化
- 深入理解java虚拟机(1) -- 理解HotSpot内存区域
- 荐 【C++100问】深入理解理解顶层const和底层const
- 深入理解 HTTPS
- 深入理解 HTTPS
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
NoSQL精粹
[美]Pramod J. Sadalage、[美]Martin Fowler / 爱飞翔 / 机械工业出版社 / 2013-8 / 49.00元
《NoSQL精粹》为考虑是否可以使用和如何使用NoSQL数据库的企业提供了可靠的决策依据。它由世界级软件开发大师和软件开发“教父”Martin Fowler与Jolt生产效率大奖图书作者Pramod J. Sadalage共同撰写。书中全方位比较了关系型数据库与NoSQL数据库的异同;分别以Riak、MongoDB、Cassandra和Neo4J为代表,详细讲解了键值数据库、文档数据库、列族数据库......一起来看看 《NoSQL精粹》 这本书的介绍吧!