实时数据观察器在创建的片段上触发两次



我遇到的问题实际上不是bug或大问题。一切都正常,但还是让我很恼火

在片段中pbserver:

viewModel.pageNumbersPosition.observe(viewLifecycleOwner) {
if (it!=null) {
SharedPreferenceHelper.pagesNumber = viewModel.pageNumbersArray.value?.get(it)
DLog.d("Set: ${viewModel.pageNumbersArray.value?.get(it)}}")
//Log shows twice as start
}
}

ViewModel:

class MenuViewModel : ViewModel() {
var pageNumbersArray = MutableLiveData(getPageNumbering())
var pageNumbersPosition = MutableLiveData(pageNumbersArray.value?.indexOf(SharedPreferenceHelper.pagesNumber))
private fun getPageNumbering():Array<String> {
val list = mutableListOf<String>()
for (i in 1..25) {
list.add(i.toString())
}
return list.toTypedArray()
}
}

Spinner:

<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@{viewModel.pageNumbersArray}"
android:selectedItemPosition="@={viewModel.pageNumbersPosition}"/>

viewModel.pageNumbersPosition.observe在启动时触发两次是什么情况。一次是从碎片开始,第二次是在旋转器设置时。这实际上是假设会发生的,但我不喜欢共享首选项设置两次。

我发现了一个方便的类SingleLiveEvent,我们可以使用它来代替ViewModel类中的LiveData,以便在订阅后只发送新的更新。

class SingleLiveEvent<T> : MutableLiveData<T>() {
private val pending = AtomicBoolean(false)
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, Observer<T> { t ->
if (pending.compareAndSet(true, false)) {
observer.onChanged(t)
}
})
}
override fun setValue(t: T?) {
pending.set(true)
super.setValue(t)
}
fun call() {
postValue(null)
}
}

如果存在对setValue()call()的显式调用,则此LiveData扩展仅调用可观察对象。

更新,带参数的主构造函数:

class SingleLiveEvent<T>(value: T) : MutableLiveData<T>(value) {...}

您可以检查共享中是否有相等的值,以避免双重设置

if (it!=null) {
viewModel.pageNumbersArray.value?.get(it).let{ value ->
if (SharedPreferenceHelper.pagesNumber != value) 
SharedPreferenceHelper.pagesNumber = value
}

}