片段返回时使用 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()
在我的 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()