尽管未更改数据,但某些片段观察器从后台堆栈弹出后触发

时间:2019-12-06 02:11:09

标签: android mvvm android-lifecycle android-livedata observers

我在Kotlin的嵌套片段中遇到了一些问题。我有ViewModel嵌套的片段。从后退按钮恢复片段后,尽管我的数据没有更改,但再次按下viewModel LiveData上的所有观察者触发器。

首先我用谷歌搜索并尝试在字段变量中定义观察者,并检查它是否已初始化,然后不再观察它:     lateinit var观察者:观察者

fun method(){
        if (::observer.isInitialized) return
        observer = Observer{ ... }
        viewModel.x_live_data.observe(viewLifecycleOwner ,observer)
}

因此,首先进入片段时它可以正常工作,并且在恢复后它不会在没有数据更改的情况下再次触发,但是在数据更改时也不会触发! 发生了什么事?

2 个答案:

答案 0 :(得分:2)

LiveData始终存储最后一个值,并将其发送给每个已注册的观察者。这样,所有观察者都具有最新状态。

在使用viewLifecycleOwner时,先前的Observer已被破坏,因此注册新的Observer绝对是正确的事情-您需要新的Observer及其现有状态来填充新的Observer返回片段后创建的(因为将片段放回堆栈时原始视图被破坏了。)

如果您尝试将LiveData用于事件(即,值仅应处理一次),则LiveData并不是最佳的API,因为您必须创建an event wrapper或类似的东西来确保它仅处理一次。

答案 1 :(得分:0)

知道发生了什么之后,我决定使用定制的实时数据来触发一次。 ConsumableLiveData 。因此,我将在此处回答可能对其他人有所帮助。

class ConsumableLiveData<T>(var consume: Boolean = false) : MutableLiveData<T>() {

    private val pending = AtomicBoolean(false)

    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        super.observe(
            owner,
            Observer<T> {
                if (consume) {
                    if (pending.compareAndSet(true, false)) observer.onChanged(it)
                } else {
                    observer.onChanged(it)
                }
            }
        )
    }

    override fun setValue(value: T) {
        pending.set(true)
        super.setValue(value)
    }
}

对于使用情况,请放在下面。任何更新值后,它将仅触发一次。这将非常适合处理导航或收听点击或用户的任何交互。因为只触发一次!

//In viewModel
val goToCreditCardLiveData = ConsumableLiveData<Boolean>(true)

然后是片段:

viewModel.goToCreditCardLiveData.observe(viewLifecycleOwner) {
        findNavController().navigate(...)

    }