Android 常用的分层架构
Android 中加载 UI 数据不是一件轻松的事,开发者经常需要处理各种边界情况。如各种生命周期和因为「配置更改」导致的 Activity 的销毁与重建。
「配置更改」的场景有很多:屏幕旋转,切换至多窗口模式,调整窗口大小,浅色模式与暗黑模式的切换,更改默认语言,更改字体大小等等
因此普遍处理方式是使用分层的架构。这样开发者就可以编写独立于 UI 的代码,而无需过多考虑生命周期,配置更改等场景。例如,我们可以在表现层(Presentation Layer)的基础上添加一个领域层(Domain Layer) 来保存业务逻辑,使用数据层(Data Layer)对上层屏蔽数据来源(数据可能来自远程服务,可能是本地数据库)。
表现层可以分成具有不同职责的组件:
View:处理生命周期回调,用户事件和页面跳转,Android 中主要是 Activity 和 Fragment
Presenter 或 ViewModel:向 View 提供数据,并不了解 View 所处的生命周期,通常生命周期比 View 长
Presenter 和 ViewModel 向 View 提供数据的机制是不同的,简单来说:
Presenter 通过持有 View 的引用并直接调用操作 View,以此向 View 提供数据
ViewModel 通过将可观察的数据暴露给观察者来向 View 提供数据
官方提供的可观察的数据 组件是 LiveData。Kotlin 1.4.0 正式版发布之后,开发者有了新的选择:StateFlow 和 SharedFlow。
最近网上流传出「LiveData 被弃用,应该使用 Flow 替代 LiveData」的声音。
LiveData 真的有那么不堪吗?Flow 真的适合你使用吗?
不人云亦云,只求接近真相。我们今天来讨论一下这两种组件。
ViewModel + LiveData
为了实现高效地加载 UI 数据,获得最佳的用户体验,应实现以下目标:
目标 1:已经加载的数据无需在「配置更改」的场景下再次加载
目标 2:避免在非活跃状态(不是
STARTED或RESUMED)下加载数据和刷新 UI目标 3:「配置更改」时不会中断的工作
Google 官方在 2017 年发布了架构组件库:使用 ViewModel + LiveData 帮助开发者实现上述目标。
相信很多人在官方文档中见过这个图,ViewModel 比 Activity/Fragment 的生命周期更长,不受「配置更改」导致 Activity/Fragment 重建的影响。刚好满足了目标 1 和目标 3。
LiveData 是可生命周期感知的。新值仅在生命周期处于 STARTED 或 RESUMED 状态时才会分配给观察者,并且观察者会自动取消注册,避免了内存泄漏。LiveData 对实现目标 1 和 目标 2 很有用:它缓存其持有的数据的最新值,并将该值自动分派给新的观察者。
LiveData 的特性
既然有声音说「LiveData 要被弃用了」,那么我们先对 LiveData 进行一个全面的了解。聊聊它能做什么,不能做什么,以及使用过程中有哪些要注意的地方。
LiveData 是 Android Jetpack Lifecycle 组件中的内容。属于官方库的一部分,Kotlin/Java 均可使用。
一句话概括 LiveData:LiveData 是可感知生命周期的,可观察的,数据持有者。
它的能力和作用很简单:更新 UI。
它有一些可以被认为是优点的特性:
观察者的回调永远发生在主线程
仅持有单个且最新的数据
自动取消订阅
提供「可读可写」和「仅可读」两个版本收缩权限
配合
DataBinding实现「双向绑定」
观察者的回调永远发生在主线程
这个很好理解,LiveData 被用来更新 UI,因此 Observer 的 onChanged() 方法在主线程回调。
背后的原理也很简单,LiveData 的 setValue() 发生在主线程(非主线程调用会抛异常,postValue() 内部会切换到主线程调用 setValue())。之后遍历所有观察者的 onChanged() 方法。
仅持有单个且最新的数据
作为数据持有者(data holder),LiveData 仅持有 单个 且 最新 的数据。
单个且最新,意味着 LiveData 每次持有一个数据,并且新数据会覆盖上一个。
这个设计很好理解,数据决定了 UI 的展示,绘制 UI 时肯定要使用最新的数据,「过时的数据」应该被忽略。
配合
Lifecycle,观察者只会在活跃状态下(STARTED到RESUMED)接收到LiveData持有的最新的数据。在非活跃状态下绘制 UI 没有意义,是一种资源的浪费。
自动取消订阅
这是 LiveData 可感知生命周期的重要表现,自动取消订阅意味着开发者无需手动写那些取消订阅的模板代码,降低了内存泄漏的可能性。
背后原理是在生命周期处于 DESTROYED 时,移除观察者。
提供「可读可写」和「仅可读」两个版本
抽象类
LiveData的setValue()和postValue()是 protected,而其实现类MutableLiveData均为 public。
LiveData 提供了 mutable(MutableLiveData) 和 immutable(LiveData) 两个类,前者「可读可写」,后者「仅可读」。通过权限的细化,让使用者各取所需,避免由于权限泛滥导致的数据异常。

本文探讨了Android中的LiveData、StateFlow和SharedFlow的使用场景,强调它们在数据更新和UI绑定中的角色。LiveData是官方架构组件,适合更新UI,具有生命周期感知和主线程回调等特性。StateFlow和SharedFlow是Kotlin协程的一部分,适用于处理异步数据流。StateFlow专注于状态管理,具有空安全和防抖功能,而SharedFlow用于事件处理,可保留历史数据。作者建议根据状态和事件的不同需求选择合适的组件,并提供了解决粘性事件和防抖问题的方案。
最低0.47元/天 解锁文章
1238





