未调用 Android LiveData 的观察器(但它与 observeForever 一起使用)

Observer for Android LiveData not called (but it is with observeForever)

我在显示项目列表的 ViewPager 上有一个 Fragment。单击一个,打开一个新的详细信息-Activity,您可以在其中操作此项目(例如更改名称)。当您 return 到列表时,我希望列表/项目反映更新。

我正在使用 RealmLiveData 的组合(添加了 RealmChangeListener 并更新了实际 LiveDatavalue)很好。

此外,我正在使用 https://medium.com/@BladeCoder/architecture-components-pitfalls-part-1-9300dd969808 中的 "reobserve" 方法 (#3),当重新添加 ViewPager 的片段时它工作正常。


当更改列表片段本身的列表项时,会调用观察器,一切正常。但是当 从不同的 activity (详细信息)进行更改时,不会调用 LiveData-observer。

然而,当使用 observeForever() 而不是 observe(LifecycleOwner) 时,观察者 被调用 即使是从另一个 activity (其中是我想要的)。


片段仅停止(当您从详细信息返回列表时恢复)。它没有分离,没有被破坏,它的视图仍然存在等等。所以 observeForever-observer 可以更新 UI 就好了(即使不可见)。

但我想使用正常 observe() 的 "add and forget" 方法,我不需要移除观察者。


有谁知道为什么不调用观察者?如前所述,片段只是停止了,视图仍然存在(当变化发生在同一个 activity 而不是不同的

时,它被调用。

因为 observeForever() 工作,我只能想到一个错误的生命周期,其中观察者被标记为 "stopped" 而不是 "resumed" 返回时?


编辑 1

根据要求,这是将 RealmResult 作为 LiveData(来自 blog post at realm)的代码:

Realm.getDefaultInstance()
  .where<Model>()
  .findAllAsync()
  .asLiveData()

fun <T : RealmModel> RealmResults<T>.asLiveData() = RealmResultsRealmData(this)

class RealmResultsRealmData<T : RealmModel>(private val results: RealmResults<T>) : LiveData<RealmResults<T>>() {

    private val listener = RealmChangeListener<RealmResults<T>> { realmResults ->
        value = if (realmResults.isValid) realmResults else null
    }

    // region LiveData

    override fun onActive() {
        results.addChangeListener(listener)
    }

    override fun onInactive() {
        results.removeChangeListener(listener)
    }

    // endregion
}

这工作得很好。我的 ViewModelonCleared() 中调用 realm.close() 所以这应该没问题。

如前所述,我不认为问题出在领域端,因为它在使用 observeForever() 时有效,但在 LiveData 上使用正常 observe() 时无效。 Realm 仅填充 LiveData 并且已验证有效(使用 observeForever())。

我最好的猜测仍然是使用 observe() 时观察者的生命周期。但是我不明白为什么当片段得到 "resumed" 时它没有被调用。 The docs 说 "observers also receive an update when they change from an inactive to an active state".

未定义 "active" 状态是什么,但我猜它至少是 "started" 并且当我从详细信息返回时我的片段进入此状态-activity。所以应该用 LiveData 的最新值调用观察者?相比之下,当使用 observeForever() 时,当我还在详细信息时立即调用观察者-activity(因为片段只是停止但仍然处于活动状态?!)。

似乎addChangeListener() 没有用当前值调用监听器

realm-examples 中的 LiveRealmResults-class 在构造函数中手动执行此操作(当结果已经加载时,因此仅适用于 synchronous查询)。

if (results.isLoaded) {
    // we should not notify observers when results aren't ready yet (async query).
    // however, synchronous query should be set explicitly.
    value = results
}

对于 async-ones,侦听器只会在查询 returns 时被调用(所以这在大多数情况下都有效,因为 LiveData 是已经 activeonActive() 已从系统调用并添加了侦听器)。


在我的例子中(模型被更改 LiveDatainactive),监听器是 未调用 当它再次激活时(如前所述,addChangeListener() 不会使用当前值调用侦听器)。

所以我的UI(观察LiveData没有收到通知并且仍然显示旧数据。


解决方法

我通过将示例构造函数中的相同行添加到 onActive()(从示例中复制)来解决这个问题。这样,当 LiveData 激活时,侦听器 被调用 并具有当前值(但在未加载结果时不会在初始调用中调用 - 因此不会重复调用)。

override fun onActive() {
    super.onActive()

    if (results.isValid) { // invalidated results can no longer be observed.
        results.addChangeListener(listener)

        if (results.isLoaded) {
            value = results
        }
    }
}