具有多个不同类型来源的 LiveData
Posted
技术标签:
【中文标题】具有多个不同类型来源的 LiveData【英文标题】:LiveData with multiple sources of different types 【发布时间】:2019-08-31 10:33:48 【问题描述】:我目前有一个项目,其中包含 MyItem
列表,并使用 Firebase/LiveData。它分为组,每个组都有项目。
如果发生以下任何情况,我希望能够更新此列表:
-
项目已更新(通过 Firebase 在后端)
过滤器已更改(Firebase 上为每个用户创建一个单独的表)
已为项目添加了书签(Firebase 上为每个用户提供了一个单独的表格)
为了获取内容列表,我有一个类似这样的函数来返回 LiveData,它会在项目更新时更新(#1)。
数据库
getList(id: String): LiveData<List<MyItem>>
val data = MutableLiveData<List<MyItem>>()
firestore
.collection("groups")
.document(id)
.collection("items")
.addSnapshotListener snapshot, exception ->
val items = snapshot?.toObjects(MyItem::class.java) ?: emptyList()
// filter items
data.postValue(items)
return data
在我的 ViewModel 中,我有处理这种情况的逻辑。
视图模型
private val result = MediatorLiveData<Resource<List<MyItem>>>()
private var source: LiveData<List<MyItem>>? = null
val contents: LiveData<Resource<List<MyItem>>>
get()
val group = database.group
// if the selected group is changed.
return Transformations.switchMap(group) id ->
// showing loading indicator
result.value = Resource.loading(null)
if (id != null)
// only 1 source for the current group
source?.let
result.removeSource(it)
source = database.getList(id).also
result.addSource(it)
result.value = Resource.success(it)
// how to add in source of filter changes?
else
result.value = Resource.init(null)
return@switchMap result
逻辑相当复杂,难以理解。有没有更好的方法来构建它来处理多个不同的变化?存储用户当前过滤器的最佳方式是什么?
谢谢。
【问题讨论】:
【参考方案1】:contents
的实现包括对外部变量的多个引用,这使得很难跟踪和跟踪状态。我只是将参考资料尽可能地保留在本地,并相信switchMap(liveData)
会做适当的工作。下面的代码应该和你的一样:
val contents = Transformations.switchMap(database.group) id ->
val data = MediatorLiveData<Resource<List<MyItem>>()
if (id == null)
data.value = Resource.init(null)
else
data.value = Resource.loading(null)
data.addSource(database.getList(id))
data.value = Resource.success(it)
return liveData
关于getList(id)
,您可能还想正确处理exception
。
【讨论】:
【参考方案2】:我不知道我是否正确地回答了您的问题,但如果您的观点适用于一个列表(类似于 MyItemList
)并且此列表在多种情况下更新或更改,您必须使用 @ 987654322@.
我的意思是你必须有三个LiveData
,每个负责一个情况,一个 MediatorLiveData 通知他们每个人都发生了变化。
见下文:
数据库
fun getListFromServer(id: String): LiveData<List<MyItem>>
val dataFromServer = MutableLiveData<List<MyItem>>()
firestore
.collection("groups")
.document(id)
.collection("items")
.addSnapshotListener snapshot, exception ->
val items = snapshot?.toObjects(MyItem::class.java) ?: emptyList()
dataFromServer.postValue(items)
return dataFromServer
fun getFilteredData(id: String): LiveData<FilterData>
return DAO.user.getFilteredData(id)
fun getBookmarkedList(id: String): LiveData<BookmarkData>
return DAO.user.getBookmarkedData(id)
在viewModel
中有一个MediatorLiveData
观察这些liveData
s,直到有任何数据更改通知视图。
视图模型
private val result = MediatorLiveData<<List<MyItem>>()
fun observeOnData(id: String, owner: LifeCycleOwner, observer: Observer<List<MyItem>>)
result.observe(owner, observer);
result.addSource(Database.getListFromServer(id), MyItemList ->
if(MyItemList != null)
result.setValue(MyItemList)
);
result.addSource(Database.getFilteredData(id), filterData ->
if(filterData != null)
val myItemList = result.getValue()
if (myItemList == null) return
//here add logic for update myItemList depend On filterData
result.setValue(myItemList)
);
result.addSource(Database.getBookmarkedList(id), bookmarkData ->
if(MyItemList != null)
val myItemList = result.getValue()
if (myItemList == null) return
//here add logic for update myItemList depend On bookmarkData
result.setValue(myItemList)
);
【讨论】:
getFilteredData()
和getBookmarkedList()
不返回MyItem
的列表,它们返回不同的对象,例如要搜索的Filter
,所以我不能简单地设置值在ViewModel
中的result
。我想我需要缓存来自getListFromServer()
的整个列表,或者我需要在获得新的Filter
后再次调用。
@Advice-Dog 在addSource
部分中,您可以添加自定义列表的任何逻辑。查看我编辑的答案。以上是关于具有多个不同类型来源的 LiveData的主要内容,如果未能解决你的问题,请参考以下文章
CoreData & RestKit - 从多个来源获取相同的实体类型
Spring批处理。如何链接具有不同类型的多个itemProcessor?
使用具有多个来源的 PUT 和 DELETE 请求时如何解决 ASP.NET Web API CORS Preflight 问题?