片段返回时使用 MVVM 清除改造结果

Clear retrofit result with MVVM when fragment back

在我的 ViewModel 中,我有两个 MutableLiveData 用于响应我的网络服务:

val getFindByCategorySuccess: MutableLiveData<List<DigitalService>> by lazy {
        MutableLiveData<List<DigitalService>>()
    }

val getFindByCategoryError: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

以及请求的此方法:

fun requestFindByCategory(categoryId: String){
        viewModelScope.launch {
            when (val retrofitPost = digitalServicesRemoteRepository.getFindByCategoryRequest(categoryId)) {
                is ApiResult.Success -> getFindByCategorySuccess.postValue(retrofitPost.data)
                is ApiResult.Error -> getFindByCategoryError.postValue(retrofitPost.exception)
            }
        }
    }

在我的 Fragment 中使用它效果很好 class :

viewModel.getFindByCategorySuccess.observe(viewLifecycleOwner, { digitalServices ->
            logD("I have a good response from the webservice; luanch an other fragment now!")
        })

问题是如果我转到我的 observable 中的另一个片段(使用 findNavController().navigate(action))。如果我回到上一个片段,我会自动转到下一个片段,因为再次调用了 observable。

所以我正在寻找解决方案... 也许当我回到我的片段时清除我所有的视图模型? 也许只清除 getFindByCategorySuccess 和 getFindByCategoryError ? 也许其他解决方案?我认为我的架构不好。你怎么看?

默认情况下,livedata 会为订阅它的任何新观察者发送其当前状态(存在于其上的值)。

回答您的问题,您可以尝试运算符 distincUntilChanged 转换,根据文档:

Creates a new LiveData object that does not emit a value until the source LiveData value has been changed. The value is considered changed if equals() yields false.

但是,这表明您的代码片段存在问题,并且是使用实时数据时常见的不良做法,您不应向观察者公开可变的实时数据。相反,您应该公开它们的 non-mutable 版本。

在我看来,您的视图模型应该如下所示:

private val getFindByCategorySuccess by lazy {
    MutableLiveData<List<DigitalService>>()
}

private val getFindByCategoryError by lazy {
    MutableLiveData<String>()
}

val onFindByCategorySuccess: LiveData<List<DigitalService>
    get() = getFindByCategorySuccess.distincUntilChanged()

val onFindCategoryError: LiveData<List<String>
    get() = getFindByCategoryrRror.distincUntilChanged()

您的观察者将订阅如下:

ExampleFragment

fun setupObservers() {
     viewModel.onFindByCategorySuccess.observe(viewLifecycleOwner) { // Do stuff }
}

希望对你有帮助

我找到了解决问题的办法 class :

class SingleLiveEvent<T> : MutableLiveData<T>() {
    private val mPending = AtomicBoolean(false)

    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        super.observe(owner, { t ->
            if (mPending.compareAndSet(true, false))
                observer.onChanged(t)
        })
    }

    override fun setValue(t: T?) {
        mPending.set(true)
        super.setValue(t)
    }

}

像这样:

var getFindByCategorySuccess: SingleLiveEvent<List<DigitalService>> = SingleLiveEvent()

var getFindByCategoryError: SingleLiveEvent<String> = SingleLiveEvent()