重学安卓5-6:吃透 LiveData 本质,为 SharedFlow 添上翅膀

作品简介
往期回顾专栏目录更新动态优惠政策版权须知
温馨提示:如这是第一次接触《重学安卓》,可通过上述链接快速了解《重学安卓》专栏,获取 专栏目录、试读内容、更新动态 和 发展状况。
截至目前,专栏已对 体系化文章 实施 3310 余次修订,数十位群友告诉我,受专栏启发 亦开启了写作之路。群里不定期会有小伙伴讨论适配问题、分享原创开源库 和 提供内推机会,订阅后可随时进群交流。

·

重要提示
阅读本文最佳时机是,您已吃过 阅读 “源码” 或 “源码分析文” 时 找不到头绪的苦
您还没吃过苦,那您先不要着急阅读本文。您得吃过苦,才会有体会。
在您吃够这方面苦后,您才有机会发现,本文正是专用于解决 “如何找到正确打开方式” 的困扰。
我们绝不通篇贴源码,而是基于广泛实践和反思,在累积过大量样本 乃至足以排除掉所有干扰信息后,点到为止揭露 LiveData 框架最核心本质,方便您理解其真实的存在意义,乃至笃信使用项目中。
关于 LiveData 在项目中实践,请另行查阅《GitHub : Jetpack-MVVM-Best-Practice》源码,及《架构模式实践》篇 完整解析。

·

注:本文重写于 2023,新文内容主要包括:
1.响应式编程的漏洞,及 LiveData 出路探索
2.LiveData 生命周期安全及粘性设计的分析与借鉴
3.LiveData 读写分离鉴权设计的分析与借鉴

前言


2020.8,StateFlow 和 SharedFlow 问世,

其中 SharedFlow 适用于发送 “一次性执行的事件”,例如 “页面跳转、showToast、弹 Dialog”,

众所周知 “弹 Dialog” 等事件,应在 “页面此时仍可见” 等情况下发生,为此官方推出 repeatOnLifecycle API,配合 SharedFlow 来实现 “生命周期安全”,

但 repeatOnLifecycle + SharedFlow 的使用存在漏洞,在 “初始化” 和 “息屏亮屏” 等场景,存在 “错过收集时机乃至错过消费” 的痛点,而 LiveData 的某个独特设计,却能为解决此类问题提供启示,

为此请跟随笔者视角,重新认识 Jetpack LiveData,相信阅读后你会耳目一新。

文章目录一览

  • 前言
  • 特质一:LiveData 是 “响应式编程” 设计
  • 什么是响应式编程
  • BehaviorSubject 和 PublishSubject 区别
  • BehaviorSubject 的潜规则
  • LiveData 是否符合 BehaviorSubject 定义
  • 更适合的 BehaviorSubject 承担,及 LiveData 出路
  • 特质二:LiveData 生命周期安全的粘性设计
  • 为何 LiveData 能做到生命周期安全
  • 为何 LiveData 能自动回推最后一次状态
  • 对 “版本号比对” 设计的借鉴
  • 特质三:LiveData 支持鉴权
  • “发布订阅模式” 和 “观察者模式” 区别
  • mutable 和 immutable
  • 对 mutable/immutable 设计的超越
  • 综上

特质一:LiveData 是 “响应式编程” 设计

什么是响应式编程


根据《响应式编程和 MVI》篇 的概括,“响应式编程” 是一种开发模式,其特征是 “向数据源请求数据,然后在 ‘指定的观察者’ 中响应数据的变化”,

也即该模式下很容易做单元测试,“有输入必有回响”。反之如像往常一样,将控件渲染的代码分散在观察者以外的各个方法中,便很难做到这一点。

BehaviorSubject 和 PublishSubject 区别


响应式编程常用的观察者有两种,一种是 BehaviorSubject,一种是 PublishSubject,

BehaviorSubject 对应的是 State,强调 “总是有一个状态”,比如门要么是开着,要么是关着,门在订阅 BehaviorSubject 时,会被自动回推最后一次 State 来反映状态,

常见的 BehaviorSubject 实现有 ObservableField、LiveData、StateFlow 等;

反之是 PublishSubject 实现,对应的是一次性事件,常见 PublishSubject 实现有 SharedFlow 等。

BehaviorSubject 的潜规则


根据《“响应式框架” 避坑与封装》篇 “隐藏坑” 一节的示例易知,BehaviorSubject 在使用时,务必确保 “同一控件实例不存在于多个 Observer 中”,并且不能误当做 PublishSubject 来使用,也即 Observer 中不能出现与状态不相干的 “一次性事件”,例如 “通知上一页刷新、弹个小窗” 等,

为此结合广泛实践得出的结论,笔者认为理想化的 BehaviorSubject 应确保 Observer 回调不被开发者触及,且 Observer 本身与目标控件一对一绑定,如此从一开始便可规避 “多观察者导致回推脏数据” 或 “在观察者回调中执行一次性事件” 等问题,

LiveData 是否符合 BehaviorSubject 定义


显然 LiveData 并没有遵循上述潜规则,它的 Observer 可被开发者直接触及,并在其回调中填入不可预测的代码,包括 “同一控件实例不存在于多个 Observer 中” 和 “Observer 中执行一次性事件” 等代码,

并且 LiveData 使用时无需赋初值,这些迹象都在表明,LiveData 既含有 BehaviorSubject 的特征,又含有 PublishSubject 的特征,其 Observer 的设计缺乏边界感,容易让人迷惑和误用。

注:相比之下,StateFlow 更贴近纯粹 BehaviorSubject 的设定,使用时须传初值,确保目标对象总是存在某状态。

更适合的 BehaviorSubject 承担,及 LiveData 出路


创作时间: