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

Live data observer triggered twice on fragment created

我遇到的问题实际上不是错误或大问题。一切正常,但仍然让我烦恼。

在片段 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
        }
}

视图模型:

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
                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 在开始时触发了两次。一次是从片段开始,第二次是在微调器设置时。这实际上应该发生,但我不喜欢共享首选项设置两次。

我遇到了一个方便的 class SingleLiveEvent,我们可以使用它代替 ViewModel class 中的 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)
    }
}

LiveData 扩展仅在显式调用 setValue()call() 时调用可观察对象。

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

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
}

}