如何解决使用LiveData和ViewModel删除项目会导致重新发射
我有一个片段,其中显示了从视图模型观察的项目列表(通过http服务,它们未持久存储在数据库中)。现在,我需要删除其中一项。我有一个删除结果实时数据,因此视图可以观察到何时删除了一个项目。
片段
fun onViewCreated(view: View,savedInstanceState: Bundle?) {
//...
viewModel.deleteItemLiveData.observe(viewLifecycleOwner) {
when (it.status) {
Result.Status.ERROR -> showDeletingError()
Result.Status.SUCCESS -> {
itemsAdapter.remove(it.value)
commentsAdapter.notifyItemRemoved(it.value)
}
}
}
}
fun deleteItem(itemId: String,itemIndex: Int) = lifecycleScope.launch {
viewModel.deleteItem(itemId,itemIndex)
}
ViewModel
val deleteItemLiveData = MutableLiveData<Result<Int>>()
suspend fun deleteItem(itemId: String,itemIndex: Int) = withContext(Dispatchers.IO) {
val result = service.deleteItem(itemId)
withContext(Dispatchers.Main) {
if (result.success) {
deleteItemLiveData.value = Result.success(itemIndex)
} else {
deleteItemLiveData.value = Result.error()
}
}
}
它工作正常,但是当我导航到另一个片段然后再次返回时,问题就来了。 deleteItemLIveData
与最后一个Result
一起发出,因此片段试图再次从适配器中删除该项目,然后崩溃。
我该如何解决?
解决方法
而不是从适配器中删除单个项目,而是更新LiveData 的原始源,因为视图会观察到该列表。
项目存储库应处理删除操作,将其从LiveData 中删除,这又将更新传播到视图,然后传播到适配器。
回购可能看起来像这样...
fun deleteItem(item: Item): Result {
val updated = items.value
updated.remove(item)
items.postValue(updated)
. . .
// propagate result of success/failure back to the view
}
fun observeItems() = items
在您的片段中,您将从单个LiveData源获得即时更新
fun onViewCreated(view: View,savedInstanceState: Bundle?) {
viewModel.observeItems().observe(viewLifecycleOwner) {
itemsAdapter.update(it) //use DiffUtil to update list or notifyDataSetChanged
}
}
}
显示错误应该是上下文,吐司消息或一些视觉通知。
更新: 删除中的处理错误可能看起来像这样,在我的头上……
suspend fun deleteItem(itemId: String,itemIndex: Int): Result = withContext(Dispatchers.IO) {
val result = service.deleteItem(itemId)
withContext(Dispatchers.Main) {
if (result.success) {
// push updated list to items
val updated = items.value
updated.remove(item)
items.postValue(updated)
Result.Success()
} else {
Result.error()
}
}
}
,
当您将LiveData
用于仅应发生一次的事件时,这是一个常见问题。 here和here解释了几种解决方案。它们要么包装发出的数据,要么包装观察者。在此包装器中,它们存储一个标志,该标志跟踪事件是否已被处理/发出。
我找到了解决方案。我更改了代码,以便从onCreate
方法而不是onViewCreated
观察片段。我也改变了主人。现在是viewLifecycleOwner
,而不是this
。这样,恢复片段时不会重新发射值,而仅在创建时或专门调用viewModel.deleteItem
时才重新发射。
现在可以正常工作。如果有人认为这是一个不好的解决方案,请告诉我。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。