如果我们以 Repository 层为界把架构蓝图分为上下两部分的话,上面的部分是数据展示,下面的部分是数据获取,数据获取部分因为要请求 Remote 数据,必然会依赖到线程调度,而数据展示必然运行在 UI 线程,与生命周期强相关,这个时候就需要 LiveData 登场了。
LiveData
LiveData 也是一个观察者模型,但是它是一个与 Lifecycle 绑定了的 Subject,也就是说,只有当 UI 组件处于 ACTIVE 状态时,它的 Observer 才能收到消息,否则会自动切断订阅关系,不用再像 RxJava 那样通过 CompositeDisposable 来手动处理。
LiveData 的数据类似 EventBus 的 sticky event,不会被消费掉,只要有数据,它的 observer 就会收到通知。如果我们要把 LiveData 用作事件总线,还需要做一些定制,Github 上搜 SingleLiveEvent 可以找到源码实现。
我们没法直接修改 LiveData 的 value,因为它是不可变的(immutable),可变(mutable)版本是 MutableLiveData,通过调用 setValue(主线程)或 postValue(非主线程)可以修改它的 value。如果我们对外暴露一个 LiveData,但是不希望外部可以改变它的值,可以用如下技巧实现:
private val _waveCode = MutableLiveData()
val waveCode: LiveData = _waveCode
内部用 MutableLiveData ,可以修改值,对外暴露成 LiveData 类型,只能获取值,不能修改值。
LiveData 有一个实现了中介者模式的子类 —— MediatorLiveData,它可以把多个 LiveData 整合成一个,只要任何一个 LiveData 有数据变化,它的观察者就会收到消息:
val liveData1 = …
val liveData2 = …
val liveDataMerger = MediatorLiveData<>();
liveDataMerger.addSource(liveData1) { value -> liveDataMerger.setValue(value))
liveDataMerger.addSource(liveData2) { value -> liveDataMerger.setValue(value))
综上,我们汇总一下 LiveData 的使用场景:
- LiveData - immutable 版本
- MutableLiveData - mutable 版本
- MediatorLiveData - 可汇总多个数据源
- SingleLiveEvent - 事件总线
LiveData 只存储最新的数据,虽然用法类似 RxJava2 的 Flowable,但是它不支持背压(backpressure),所以不是一个流(stream),利用 LiveDataReactiveStreams 我们可以实现 Flowable 和 LiveData 的互换。
如果把异步获取到的数据封装成 Flowable,通过 toLiveData 方法转换成 LiveData,既利用了 RxJava 的线程模型,还消除了 Flowable 与 UI Controller 生命周期的耦合关系,借助 Data Binding 再把 LiveData 绑定到 xml UI 元素上,数据驱动 UI,妥妥的响应式。于是一幅如下模样的数据流向图就被勾勒了出来:
图中右上角的 Local Data 是 AAC 提供的另一个强大武器 —— ORM 框架 Room。
Room
数据库作为数据持久层,其重要性不言而喻,当设备处于离线状态时,数据库可用于缓存数据;当多个 App 需要共享数据时,数据库可以作为数据源,但是基于原生 API 徒手写 CRUD 实在是痛苦,虽然 Github 上出现了不少 ORM 框架,但是它们的易用性也不敢让人恭维,直到 Room 出来之后,Android 程序员终于可以像 mybatis 那样轻松地操纵数据库了。
Room 是 SQLite 之上的应用抽象层,而 SQLite 是一个位于 Android Framework 层的内存型数据库。虽然 Realm 也是一个优秀的数据库,但是它并没有内置于 Android 系统,所会增大 apk 的体积