某些片段观察器在从后退堆栈弹出后触发,尽管数据不会更改



我在 Kotlin 中的嵌套片段中遇到了一些问题。我用视图模型嵌套了片段。从后退按钮恢复片段后,再次按视图上的所有观察者模型实时数据触发器,尽管我的数据没有改变。

首先,我用谷歌搜索并尝试在归档变量中定义观察器并检查它是否已初始化,然后不要再次观察它: lateinit var observer: Observer

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

因此,首先输入碎片它工作正常,并且在恢复后它不会在没有数据更改的情况下再次触发,但它也不会在数据更改时触发! 这是怎么回事?

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

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

如果您尝试将 LiveData 用于事件(即,只应处理一次的值(,LiveData 不是最好的 API,因为您必须创建事件包装器或类似的东西以确保它只处理一次。

在知道发生了什么之后,我决定使用自定义的实时数据来触发一次。可消费实时数据。所以我会把答案放在这里可能会帮助别人。

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(...)
}

如果您使用的是 Kotlin 并且只触发一次数据/事件,请使用MutableSharedFlow

例:

private val data = MutableSharedFlow<String>() // init
data.emit("hello world) // set value
lifecycleScope.launchWhenStarted {
data.collectLatest { } // value only collect once unless a new trigger come
}

MutableSharedFlow不会触发方向更改或返回到上一个片段等

最新更新