Android 虽然数据没有改变,但一些片段观察器在从后堆栈弹出后触发

Android 虽然数据没有改变,但一些片段观察器在从后堆栈弹出后触发,android,mvvm,android-lifecycle,android-livedata,observers,Android,Mvvm,Android Lifecycle,Android Livedata,Observers,我在Kotlin的嵌套片段中遇到了一些问题。我使用ViewModel创建了嵌套片段。从后退按钮恢复片段后,再次按下viewModel LiveData触发器上的所有观察者,尽管我的数据没有更改 首先,我在谷歌上搜索并尝试在字段变量中定义观察者,检查它是否已初始化,然后不再观察它: lateinit var观察者:观察者 fun method(){ if (::observer.isInitialized) return observer = Observer{ .

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

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

fun method(){
        if (::observer.isInitialized) return
        observer = Observer{ ... }
        viewModel.x_live_data.observe(viewLifecycleOwner ,observer)
}
因此,在第一次输入片段时,它工作正常,并且在恢复之后,它不会在没有数据更改的情况下再次触发,但在数据更改时也不会触发!
发生了什么?

LiveData
始终存储最后一个值,并将其发送给注册的每个观察者。这样,所有观察者都能了解最新情况

当您使用
viewLifecycleOwner
时,您以前的观察者已被销毁,因此注册新观察者绝对是正确的做法-您需要新观察者及其现有状态来填充返回片段后创建的新视图(因为当片段放在后堆栈上时,原始视图会被破坏)


如果您试图将LiveData用于事件(即,只应处理一次的值),LiveData并不是最好的API,因为您必须创建或使用类似的API来确保它只被处理一次。

知道发生了什么后,我决定使用定制的实时数据来触发一次。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)
    }
}

奇怪的是,在恢复片段上没有任何更改数据的情况下,所有观察者都会再次触发。当您将该片段放在后堆栈上时,您以前的
observe
会被删除。您再次调用
observe
,这意味着您将被发送到当前状态。这就是它的工作方式,否则您的新视图实际上不会被激活有任何数据。也许你是对的。我使用一些liveData来观察用户事件。例如,单击,在恢复后,我认为数据仍然存在。单击再次发生。我是对的吗?这就是我回答的最后一段所说的,是的。好的,让我检查一下。
//In viewModel
val goToCreditCardLiveData = ConsumableLiveData<Boolean>(true)
viewModel.goToCreditCardLiveData.observe(viewLifecycleOwner) {
        findNavController().navigate(...)

    }