本文原始发表于:https://juejin.cn/post/6955726530911666190
借助 LiveData 的能力,在 View(Activity 或者 Fragment)和 ViewModel 之间,使用 LiveData 通信,当 LiveData 发生变化的时候,订阅了该 LiveData 的 View 能够收到通知以便做出相应的更新 UI 逻辑。
这种特性对于那种需要持续监听数据变化,然后实时做出 UI 响应的场景十分有用且便利。
然而,这里有个细节需要注意:View 在 observes LiveData 的那一刻,便能收到一次通知,拿到当前 LiveData 的值。换句话说,我们可以在监听 LiveData 的时候,拿到监听之前设置给 LiveData 的值 —— 我们称之为粘性消息。
但是有时候,我们并不希望在监听的时候拿到「上一次的值」。比如我们实现收款到账提醒的功能,我们希望每次有新收到账的时候,发送一个到账通知的提醒,假设我们监听之前,已经有到账记录了,这时候如果我才开始监听,然后提醒我有新的到账(实际上是上一次的到账),这就有问题了。
LiveData 的这种特性,这并不是一个 Bug,LiveData 设计之初并不是给我们用来当成 EventBus 使用的,而是用于监听「状态」的,此处引用官博的原文
Instead of trying to solve this with libraries or extensions to the Architecture Components, it should be faced as a design problem.
如何理解状态(state)和事件(event)?
简单理解:「状态」可以持续一段时间,而「事件」指某一刻发生的事情
拿一个简单的例子举例:开灯和关灯
- 关灯和开灯可以理解为是两次事件的发生,而灯是亮的和灯是灭的则是两种状态;
- 灯亮之后可以获取灯的状态(状态一直在持续),但无法知道是什么时候开灯的(事件是之前发生的,转瞬即逝)
- 事件的触发可以让状态发生转换
而 LiveData 的特性「监听时能够接收到监听之前已经改变的状态」正是为了「状态」而设计的。因此,并不是所有场景下都适合使用 LiveData,当我们所要监听的数据是符合「状态」特性,而是不是「事件」特性的时候,才是最适合使用 LiveData 的场景。
LiveData 常见的几种错误使用姿势
前文之所以花费这么大篇幅介绍 LiveData 的「粘性消息」特性,一是为了让大家对 LiveData 有更深一步的认识,了解其设计之初的目的才知道什么时候该用,什么时候不该用,二是因为如果我们不了解这个特性,很容易引发问题。下面分别介绍几种常见错误使用方式:
case 1:数据是「事件」类型的
以「收款到账提醒举例」
class MvvmViewModel : ViewModel() {
private val _billLiveData = MutableLiveData<String>()
val billLiveData: LiveData<String>
get() = _billLiveData
fun pay(msg: String) {
_billLiveData.value = msg
}
}
class MvvmActivity : AppCompatActivity() {
private val viewModel by viewModels