转载请注明出处:http://blog.youkuaiyun.com/My_TrueLove/article/details/52305792
访问 ruicb.com,一键抵达我的博客!
主要内容:ViewTreeObserver
是被用来注册监听视图树的观察者,在视图树发生全局改变时将收到通知。本文从 ViewTreeObserver
源码出发,带你剖析 ViewTreeObserver
的设计及使用,并间接体会观察者模式、Android消息传递机制在其中的使用。
这两天看代码看到了 ViewTreeObserver
,之前有接触过,但一直不太其到底在表达什么。这次既然又碰到了,那就干脆研究一下吧。于是我开始以关键字“ViewTreeObserver” Google 相关内容,结果发现找到的内容都差不多,更有甚者通篇直接翻译api,惊呆了!真的一点都不夸张,不相信的可以自己搜索试试看…
本系列分为上下两篇,本篇较为基础,主要介绍 ViewTreeObserver
的基础信息,以及说一下观察者模式,至于消息传递以及实战等更多内容将在下篇介绍。
1. 分开理解 ViewTreeObserver
ViewTreeObserver
,拆开来理解就是 ViewTree
和 Observer
。
ViewTree
就是我们常说的视图树,在Android中,所有视图都是由View及View的子类构成,ViewGroup 也是View的子类,它可以装载View或者ViewGroup,这样,一层层嵌套,就有了视图树的概念。给一张图感受一下:
Observer
即观察者的意思,其对应的观察者模式是软件设计模式的一种,在许多编程语言中被广泛运用。其核心在于:一个目标对象,我们称之为被观察者(Observable),管理着所有依附于它的观察者(Observers),当被观察者发生某种改变时(称为事件),被观察者调用对该事件感兴趣的观察者所提供的方法,主动通知观察者。
总结起来就是三要素:观察者,被观察者,事件,图示如下,图画的有点虚。
至于在 ViewTreeObserver
中,观察者模式是如何工作的,需要留到后面再说了,因为涉及到 View 的 measure、layout 和 draw 等过程。等不及的可以自己看一下,给点提示:看 ViewRootImpl
类。
2. ViewTreeObserver 概念
分别介绍 ViewTree
和 Observer
之后,我们就不难理解 ViewTreeObserver
的概念了。在这里,ViewTree
即为被观察者(也可以是单个View),ViewTreeObserver
就是观察者,ViewTreeObserver
对 ViewTree
注册监听(观察它),当 ViewTree
发生某种变化时,将调用 ViewTreeObserver
的相关方法,通知其这一改变。我们要做的就是覆写这一方法,添加自己的逻辑。
来看一下官方文档的注释说明:
ViewTreeObserver
是被用来注册监听视图树的观察者,在视图树发生全局改变时将收到通知。这种全局事件包括但不限于:整个视图树的布局发生改变、在视图开始绘制之前、视图触摸模式改变时…
3. 获取 ViewTreeObserver 对象
了解了 ViewTreeObserver
之后,接下来说说如何获取 ViewTreeObserver
对象。我想大多数人会想到 new ViewTreeObserver()
,因为这个我们最擅长了。
但是,ViewTreeObserver
的构造方法明确声明了:This constructor should not be called。也就是我们没法调用,当我们尝试这么做时,IDE 会提示:
'ViewTreeObserver()' is not public in 'android.view.ViewTreeObserver'.Cannot be accessed from outside package
根据 ViewTreeObserver
类的注释可知,我们只能通过 View 的 getViewTreeObserver()
方法获取 ViewTreeObserver
对象,那么我们看一下 getViewTreeObserver()
方法的源码:
先介绍一下方法中的 AttachInfo
,官方文档如此注释说明:
A set of information given to a view when it is attached to its parent
意思是:当这个 View 被附着到父窗口时,将会获得这一组信息。说的好抽象啊,还是自己这组信息都有啥吧。
AttachInfo
是 View 类的内部类,找到这个类,浏览一遍,发现其含了一个 ViewTreeObserver
对象,以及该 View 所处的窗口(Window)、设备(Display)、根视图(rootView)等信息,信息量还是蛮大的,感兴趣的可以自己了解下,我们目前只关心这个 ViewTreeObserver
对象。
下面分析方法的逻辑。这个方法首先判断 View 所持有的 mAttachInfo
,当 mAttachInfo
不为空时,直接返回 mAttachInfo
中的 ViewTreeObserver
对象;否则去判断 View 类的 ViewTreeObserver
对象 mFloatingTreeObserver
,若 mFloatingTreeObserver
为空,则创建该对象,并返回。
对于 mFloatingTreeObserver
,官方注释为:
Special tree observer used when mAttachInfo is null.
很明显,这是一个特殊的视图树观察者对象,只有当 mAttachInfo
为空时才会被使用。
至此,我们成功的获取了 ViewTreeObserver
对象。
4. 确保 ViewTreeObserver 可用
在前面,我们成功获取了 ViewTreeObserver
对象,当我们使用该 对象调用 addOnXxxListener
方法监听 View 的某个状态时,该方法总是首先调用 checkIsAlive()
方法,检测 View 的 ViewTreeObserver
对象是否存活(可用)。
为什么要先去检测呢?官方文档给出的解释是:通过 View 的 getViewTreeObserver()
方法返回的 ViewTreeObserver
,在 View 的生命周期中不能保证始终有效。
既然我如此,那么通过源码我们看一下 checkIsAlive()
都做了什么:
逻辑还是很简单的:如果 View 的 ViewTreeObserver 对象不可用,将抛出 IllegalStateException
(非法状态异常),并提示我们 重新调用 View 的 getViewTreeObserver()
方法获取对象。
但是,我们能不能在调用 addOnXxxListener
之前,能否检测当前 View 的 ViewTreeObserver
对象是否可用呢,总不能每次等异常了才发现要去重新获取把?答案是肯定的!
ViewTreeObserver
为我们提供了 isAlive()
方法,逻辑很简单,就一句代码“return mAlive”,mAlive
就是在 checkIsAlive()
方法中所判断的变量。该变量标记当前 View 的 ViewTreeObserver
对象是否可用。
最后,翻译官方文档的注释,来总结如何确保 ViewTreeObserver
可用:
当 ViewTreeObserver
不可用时,调用 isAlive()
方法以外的任何其他方法,都将抛出异常。所以,如果 View 对 ViewTreeObserver
持有长时间引用,那么其应该在调用 ViewTreeObserver
对象的任何其他方法之前,确保通过 isAlive()
的返回值检查 ViewTreeObserver
的状态是否可用。
5. 结尾
至此,有关 ViewTreeObserver
的基础只是介绍就到这儿了,相信你一定会觉得没看过瘾,因为本篇只是介绍了 ViewTreeObserver
的概念、如何获取View实例,以及如何避免 ViewTreeObserver
对象为空,我也觉的说的有点简单了。但是,当你发现这些网上都没有,需要靠自己读源码和注释去了解时,就不是那么简单了。
下篇预告:ViewTreeObserver
的 API 介绍、观察者模式是如何起作用的、View 涉及的消息传递机制 以及 ViewTreeObserver
的使用等,统统放出来。请耐心等候,这期间不妨自己去看看源码。
最后,感谢你耐心看完,看完之后有任何问题,欢迎随时交流。
下篇已更新:《解析 ViewTreeObserver 源码,体会观察者模式、Android消息传递(下)》
扫描下方二维码,关注我的公众号,及时获取最新文章推送!