Android Architecture Components 源码分析 第三篇

本文已授权我就是马云飞公众号独家发布。

说是源码分析有点,其实就是简单的根据源码梳理一遍整体的LiveData,ViewModel和Lifecycle各个部分是如何工作的,由于本人水平有限,如果文中有错误的地方,欢迎指正。

Android Architecture Components 源码分析系列文章

  1. Android Architecture Components 第一篇,介绍生命周期的感知。
  2. Android Architecture Components 第二篇,介绍ViewModel的控制。
  3. Android Architecture Components 第三篇,介绍LiveDate和LifeRegistry的协同操作。

这个是Android Architecture Components(简称AAC)的第三篇,之前的两篇 文章分别介绍了Lifecycle和ViewModel的生命周期,这篇主要讲的就是最开始提出的第三个问题LiveData数据的控制。

简单案例

先列举一个简单的例子,看看如何使用的

在ViewModel中有LiveData的成员变量,然后添加一个观察者。在ViewModel中

在ViewModel中就是拥有一个成员变量,加上对应的get方法,修改数据的时候直接使用setValue更新,这样就会弹出一个Toast。

使用起来并不难,但我们的目的是了解如何实现的。

案例分析

关于上文的例子,从三个部分开始分析,一是添加观察者的时候,二是生命周期的控制,三是设置数据的时候。

添加观察者

  1. 先判断一下LifecycleRegistry当前的状态,如果是DESTORYED的话,就直接返回。
  2. 之后是将LifecycleOwner和创建Observer封装到LifecycleBoundObserver中。
  3. 从当前的Oberver集合中查找没有传入的Observer对应的包装类,如果有则返回,没有则添加。
  4. LifecycleRegistry添加包装之后的LifecycleBoundObserver观察者。
  5. 更新下当前的包装类的状态。

这里需要理解并记住的是LifecycleBoundObserver是一个拥有真正回调Observer和LifecycleOwner的封装类。

在LifecycleRegistry中添加观察者,这个LifecycleRegistry是在Activity/Fragment中创建的成员变量。

  1. 确定初始时LifecycleBoundObserverd的状态,这里大部分的情况都是INITIALIZED,除非把之前的observe写在onDestory中,不过估计一般没人这么写。
  2. 将传入的LifecycleBoundObserver和确定的状态封装到一个statefulObserver。在这个过程中会对observer进行一定转化,将其改变成另一种LifecycleObserver,然后再使用的时候会通过反射去调到实际需要的方法。
  3. 将封装过的statefulObserver和传入的observer添加到当前的一个map中进行保存,如果之前已经添加过的话,就直接返回旧的,没有的话再放入,返回null。
  4. 判断是否可以重入,来决定是否进行同步,这里的parentState暂时先不考虑,等最后的时候再分析。
  5. 其中while循环的部分是为了修改刚添加进去的ObseverWithState中state的状态。
  6. sync方法是事件传递的关键,在之后也会用到,就先不分析。

接下来看一下当生命周期变化的时候会发生什么?

生命周期改变

根据第一篇文章中我们可以知道当应用的生命周期变化的时候,会发送对应的生命周期事件到LifecycleRegistry的handleLifecycleEvent方法中进行处理,这里先简单的分析下逻辑。

首先设置当前的LifecycleRegistry中的mState值,之后执行sync方法

这里先判断一下是否可以进行同步,判断的条件是当前map中的oberver数量和状态,之后会根据当前的mObserverMap中保存的observer的状态和当前的Registry的状态进行比较,来决定是进行正推计算还是反推计算。先以正推计算为例:

把当前的mObserverMap中的数据进行迭代,判断状态之后执行observer.dispatchEvent()方法,来同步Observer

这里会先设置当前的Observer的状态,之后会调用Observer的onStateChanged方法,这个方法会经过一系列的变化,通过反射,最终调到LiveData中的LifecycleBoundObserver的onStateChage()方法

这两个方法最主要的作用就是判断当前的LifecycleOwner是否是active状态。如果是active状态的话就刷新数据。

数据更新

上面正好讲到刷新数据,我们来继续说一下当setvalue的时候发生了什么:

可以看到将成员变量mData赋值 ,之后也是调用了相同的dispatchingValue方法

这里的关键函数就是considerNotify,如果是通过setValue方法进行更新的话,会更新所有的observer,如果是通过handleLifecycleEvent方法进行更新的话,那么只会更改当前的observer。

首先会先检查当前的observer的active,之后会检查observer的owner的状态是否是可用的,再判断当前的版本。最后进行更新数据。

小结

到这里其实整体的生命周期事件的观察和传递,同步和更新,修改数据,都已经简单的介绍完毕了,单单拿出来一个部分其实并不难理解,主要需要明白并记住的就是LifecycleRigestry的mState、Event、ObserverWithState的mState和LifecycleBoundObserver的active。事件的来源只有一种就是handleLifecycleEvent,最终的目的地就是为了修改ObserverWithState的mState和LifecycleBoundObserver的active。

整体流程分析

每一个小部分的功能都有所了解的之后,让我们尝试下梳理最上面的案例中整个事件的传递。这里添加订阅者是在onCreate方法中。先上个我自己画的图,方便理解。

这个是我自己梳理的整体的事件流程和刷新的图。根据这个图来介绍下执行的流程。

  1. 由于上面的案例是在onCreate中订阅的,那么最开始先执行的应该是addObserver,这个时候会把LifecycleRegistry的mState(下文简称RS)置为INITIALIZED。并向observerMap中添加封装过的ObserverWithState,其中的mState(下文简称OS)为INITIALIZED。不执行同步方法。

  2. Activity启动,传递过来第一个生命周期事件ON_CREATE,通过getStateAfter计算之后的State为CREATED赋值给RS,判断状态决定执行正推计算,OS的当前值为INITIALIZED,更改LifecycleBoundObserver的active(下文简称active)值为false。OS修改为CREATED。

  3. 事件ON_START,RS为STARTED,正推计算,OS当前值为CREATED,更改active为true。OS修改为STARTED。

  4. 事件ON_RESUME,RS为RESUMED,正推计算,OS当前值为STARTED,更改active为true。OS修改为RESUMED。

  5. 事件ON_PAUSE,RS为STARTED,反推计算,OS当前值为STARTED,更改active为true。OS修改为STARTED。

  6. 事件ON_STOP,RS为CREATED,反推计算,OS当前值为CREATED,更改active为false。OS修改为CREATED。

  7. 事件ON_DESTROY,RS为DESTROYED,反推计算,OS当前值为DESTROYED,更改active为false。OS修改为DESTROYED。

整体事件流程就是这样,通过感知Activity/Fragment的生命周期,然后分发到LifecycleRegistry中进行处理,根据当前的状态来修改保存的ObserverWithState的mState,然后修改LifecycleBoundObserver的active决定数据是否可以更新。

上面的状态都是作者根据最开始的案例断点调试得出的结论,值得注意的就是因为有Application也就是ProcessLifecycleOwner的干扰,调试的时候要区分好LifeRegistry,第二个注意的就是mState的值,因为有两个mState,经常会需要进行比较,来决定同步。

总结

至此,整个Android Architecture Components架构中所有的源码都过了一遍了, 主要的难点就是在handleLifecycleEvent()和Sync()两个方法。总体的分析下整个架构:

个人认为主要分为三个部分:

第一部分:生命周期的感知包括系统生命周期的感知。其中有使用的类和技巧有,通过注册ContenProvider进行项目的初始化,通过添加Fragment来获取宿主的生命周期。通过给Application和Activity添加生命周期的回调,来进行Fragment的初始化和生命周期的感知。

相关的类包括:
LifecycleRuntimeTrojanProvider 用于进行初始化init操作
LifecycleDispatcher 用于进行生命周期分发处理
ProcessLifecycleOwner 应用生命周期控制 ,、
ReportFragment 添加的Fragment 用于感知宿主生命周期

第二部分:ViewModel生命周期的控制。同样使用了添加Fragment来感知宿主的生命周期,通过一个HoldFragment来持有一个ViewModelStore保存当前宿主的所有ViewModel,通过工厂模式反射获得ViewModel对象。

相关的类包括:
ViewModel
ViewModelProvider ViewModel的提供者
ViewModelStore 用于保存ViewModel
HolderFragment 添加的Fragment 用于感知宿主生命周期等。

第三部分:LiveData和LifecycleRegistry的协同操作。这里使用了两个枚举对象来概括整体的生命周期,通过Event的传递来改变当前的Lifecycyle的状态,同时更新当前的Observer是否处于活动状态。个人认为整个项目中的关于Observer的三个封装类是整个项目的骨架,State和Event就是流动血液,而HandleLifecycleEvent和Sync两个方法就是整个项目的灵魂。

相关的类包括:
LiveData 数据模型
LifecycleOwner 生命周期持有者
LifecycleRegistry 用于控制生命周期
ObserverWithState 保存Observer和对应的状态
LifecycleBoundObserver 保存Observer和LifecycleOwner
ReflectiveGenericLifecycleObserver 反射调用的相关类

学习收获

这不是我第一次去深入的研究系统的源码了,不过每一次看源代码真的都能带来新的收获和想法。在学习AAC的过程中,最大的收获感觉还是对AAC项目的熟悉,能够清楚的知道每一个类,每一个方法,每一个成员变量的作用,是用来做什么的,什么起作用。当我看到它们的类名就能够知道他们是做什么的,这种熟悉感,我觉得是最大的收获。其次是在研究源码过程中一些心得体会,遇到难度高的地方的时候适当的放松,真的会有助于解决问题,我这里有好几个关键点都是我下楼散步的时候想到的为什么。

最后想要说的就是对于知识的渴望程度,或者说对于知识的了解程度,我觉得这种概念适用于所有领域,以AAC这个框架为例

  1. 会使用,能够写代码
  2. 知道原理,了解源代码是什么实现的,知道每一个部分的原理,功用。
  3. 能够修改,在原有的基础上进行修改,使其变得更优或者更适用于自己。

目前在学习第三方框架的时候,都在遵循着三点,争取都能够达到第二层次,部分简单的项目可以实现第三层次。这好比练武功,从登堂入室,再到烂熟于心,再到推陈出新。

会用的人太多,而知道为什么的人太少。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容