ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Android mvvm 之 LiveData 的原理,android开发者模式

2022-01-03 11:00:11  阅读:176  来源: 互联网

标签:状态 生命周期 mvvm LifecycleOwner 观察者 LiveData 非关键 Android


我们看一下关键的源代码:

// 入口

@MainThread

protected void setValue(T value) {

// 必须在主线程调用

assertMainThread(“setValue”);

//…省略非关键代码

// 设置新值并派发通知

mData = value;

dispatchingValue(null);

}

// 通知派发流程

void dispatchingValue(@Nullable ObserverWrapper initiator) {

//…省略非关键代码

// 遍历观察者列表

for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =

mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {

// 尝试通知观察者

considerNotify(iterator.next().getValue());

//…省略非关键代码

}

}

其中 LiveData.considerNotify() 在 2.1 节中已有说明。

4 LifecycleOwner 的事件变化

对于 LifecycleOwner 来说,其变化的事件即为生命周期状态的变化。在 LifecycleOwner 的事件委托者 Lifecycle 看来,无论是发生了 ON_CREATE 事件还是 ON_START 事件,或是任何其它的事件,其事件的切换流程都是通用的。

换言之,只要 Lifecycle 接口的实现者实现这一通用切换流程,便只需给 LifecycleOwner 暴露一个切换入口,就能在 LifecycleOwner 的各个生命周期回调函数中调用这个入口就可以了。这样我们在 LifecycleOwner 中应该可以看到形如这样的流程(伪代码表示):

public class Activity/Fragment implements LifecycleOwner {

@Override

public onCrate() {

//…省略非关键代码

// 在 Jetpack 框架中,LifecycleImpl 被命名为 LifecycleRegistry

LifecycleImpl.handleLifecycleEvent(ON_CREATE);

}

@Override

public onStart() {

//…省略非关键代码

LifecycleImpl.handleLifecycleEvent(ON_START);

}

@Override

public onResume() {

//…省略非关键代码

LifecycleImpl.handleLifecycleEvent(ON_RESUME);

}

@Override

public onPause() {

//…省略非关键代码

LifecycleImpl.handleLifecycleEvent(ON_PAUSE);

}

@Override

public onDestroy() {

//…省略非关键代码

LifecycleImpl.handleLifecycleEvent(ON_DESTROY);

}

}

当然,在具体的源代码中,与上述伪代码会有一些出入,但是大体的结构是一致的。在 Jetpack 框架中,这个 Lifecycle 的实现者叫做 LifecycleRegistry。所以我们这里重点需要关注的就是 LifecycleRegistry 这个 Lifecycle 的代理接口的实现类是如何通知生命周期事件变化的。

4.1 Lifecycle 接口的实现——LifecycleRegistry

4.1.1 LifecycleRegistry 的订阅实现

如 2.2 节所述,通过 LiveData.observe(owner, user-defined observer),LifecycleOwner 的业务层向 LiveData 订阅数据变化,而在 LiveData.observe() 方法内,同时会自动通过 Lifecycle.addObserver(LiveData-defined observer) 向 LifecycleOwner 订阅生命周期变化:

// LiveData.observe()

@MainThread

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {

//…省略非关键代码

LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

//…省略非关键代码

// 向 LifecycleOwner 发起订阅

owner.getLifecycle().addObserver(wrapper);

}

以上方法内的 owner.getLifecycle() 的实际对象即为 LifecycleRegistry,我们来看一下 LifecycleRegistry.addObserver() 的基本订阅流程:

lifecycleregistry_addobserver.png

从整个流程来看,总体可以分为三步:

  • 第一步是初始化观察者对象的状态,并将观察者缓存入队;

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整资料开源分享

  • 第二步是以模拟派发生命周期事件的形式,将新加入的观察者的状态提升到目前为止可提升的最大状态;

  • 第三步是同步所有观察者的状态到全局状态。

我们可以看到,最后所有的观察者的状态都要同步到全局状态,全局状态即为 LifecyclerOwner 最新的状态。那么为什么需要进行这么繁琐的逐步模拟派发事件来进行同步呢?直接一步到位不行么?

我们可以考虑一个生命周期感知组件 LifeLocation,其功能是用于进行定位,它订阅了 LifecycleOwner,我们假设 LifeLocation 需要在 CREATED 的时候进行一些必要的初始化,而在 STARTED 的时候开始执行定位操作。假如在 LifecycleRegistry 中的状态同步可以一步同步到全局状态,那么有可能当前的全局状态已经是 RESUMED 的了,这样 LifeLocation 既得不到初始化,也无从启用定位功能了。

所以,以上这种看似繁琐的模拟派发状态事件的步骤是完全必要的,它让用户自定义的生命周期感知组件的状态切换流程是可预测的。

4.1.2 LifecycleRegistry 中的事件流

我们在 4.1.1 节中的流程图的第 6 步中提到,要根据 observer.state 来计算下一个状态事件,也就是说按照事件的流向,根据当前的状态,下一个要发生的事件是什么。我们修改一下 1.2 节的时序图如下:

lifecycleregistry_event_flow

观察到图中左边的蓝色箭头,举个例子,假如当前的状态是 CREATED,那么接下来要发生的事件应该是 ON_START。蓝色箭头指示的事件流方向是生命周期由无到生的过程,我们称为 upEvent 流;与此对应,右边的红色箭头指示的事件流方向是生命周期由生到死的过程,我们称之为 downEvent。

4.1.1 节中的流程图的第 6 步中正好需要进行 upEvent 流操作。除此以外,我们在第 7 步同步到全局状态时,还需要用到 upEvent 和 downEvent 流操作,且在 LifecycleOwner 的每一次生命周期的变化中,都需要进行上述第 7 步的状态同步操作。接下来我们就看一看,当 LifecycleOwner 生命周期变化后,发生了什么。

4.1.3 处理生命周期的变化

在 4 节开头我们描述了 LifecycleImpl.handleLifecycleEvent() 方法,在 LifecycleRegistry 中也有一个同名的方法,其功能就是处理 LifecycleOwner 生命周期的变化。handleLifecycleEvent() 的处理过程是这样的:

handlelifecycleevent

如图所示:

  • Sync 标记的部分是进行状态同步的核心流程,同时也是 4.1.1 节流程图中的第 7 步的具体实现;

  • 每一次生命周期的变化有可能是从无到生的 up 变化,也有可能是从生到死的 down 变化;

  • 如果是 up 变化,则需要进行 upEvent 流处理,如果是 down 变化,则需要进行 downEvent 流处理;

  • 根据 4.1.1 节的描述,我们可以得出,在观察者队列中的所有观察者,从最老(最开始)到最新(最末),必定维持一个不变性质:非降序排列;

  • 所以当 STATE < eldestState 时,说明观察者队列中的所有观察者状态都大于全局状态,这时候说明生命周期变化顺序是 down 方向的,需要进行 downEvent 流处理;

  • 而当 STATE > newestState 时,说明观察者队列中的所有观察者状态都小于全局状态,这时候说明生命周期变化顺序是 up 方向的,需要进行 upEvent 流处理;

  • 无论是 downEvent 流还是 upEvent 流,都会逐步派发生命周期事件给各个观察者。

关于 downEvent 流和 upEvent 流,我画了一张更加形象的图用以加深理解:

downevent_and_upevent

至此,整个 LiveData 和 Lifecycle 的原理就介绍完成了。

5. 关于观察者模式的一点思考

不难看出,LiveData 和 Lifecycle 的核心是观察者模式。无论是 LiveData 还是 Lifecycle,它们的共同点就是都需要维护一个稳定的状态机:

  • LiveData 的状态机就是数据值的变化,每个值就是一个状态,理论上可以是一个无限状态机;

  • Lifecycle 的状态机就是生命周期的变化,每个生命周期阶段就是一个状态,它是一个有限状态机。

在涉及到状态机模型时,如果我们需要感知状态机当前的状态,一般有两种方式:主动询问和被动通知。在复杂的业务中,主动询问状态机往往是不好的实践;而被动通知,可以让我们的业务按照状态进行清晰的分段,更易于模块化和测试。观察者模式就是一种很好的被动通知模式。

所以,当我们的对象维护了一个状态机的时候,可以考虑是否可以采用观察者模式来读取状态。但是需要注意的是,观察者模式内部是维护了一个观察者引用的列表的,当状态发生变化的时候,是采用顺序遍历的方式逐个进行通知的,可以想到,当一个被观察者中维护的观察者数量很多,其中又有很多观察者对状态的响应处理都比较耗时的话,会出现性能瓶颈。尤其是在基于单线程的 UI 环境下,更加需要引起注意,我们通常应该有一个机制来移除不再需要的观察者,以减轻通知负载。

说明:

该文档参考的 androidx 版本为

core: 1.1.0

lifecyle: 2.2.0-alpha01

fragment: 1.1.0-alpha09

最后


小编学习提升时,顺带从网上收集整理了一些 Android 开发相关的学习文档、面试题、Android 核心笔记等等文档,希望能帮助到大家学习提升,如有需要参考的可以直接去我 CodeChina地址:https://codechina.csdn.net/u012165769/Android-T3 访问查阅。

标签:状态,生命周期,mvvm,LifecycleOwner,观察者,LiveData,非关键,Android
来源: https://blog.csdn.net/flunsna/article/details/122284908

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有