具有多个不同类型来源的 LiveData
LiveData with multiple sources of different types
我目前有一个包含 MyItem
列表并使用 Firebase/LiveData 的项目。它被分成组,每个组都有项目。
如果发生以下任一情况,我希望能够更新此列表:
- 项目已更新(通过 Firebase 在后端)
- 过滤器已更改(每个用户在 Firebase 上单独 table)
- 一个项目已添加书签(每个用户在 Firebase 上单独 table)
为了获取内容列表,我有一个类似这样的函数 return 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
}
}
逻辑很复杂,很难理解。有没有更好的方法来构建它来处理多个不同的变化?存储用户当前过滤器的最佳方式是什么?
谢谢。
我不知道我是否正确地回答了你的问题,但如果你有一个适用于一个列表的视图(类似于 MyItemList
)并且这个列表在几种情况下更新或更改,你必须与 MediatorLiveData
.
一起工作
我的意思是你必须有三个 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
直到有任何数据改变通知视图。
viewModel
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)
}
});
}
您对 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
。
我目前有一个包含 MyItem
列表并使用 Firebase/LiveData 的项目。它被分成组,每个组都有项目。
如果发生以下任一情况,我希望能够更新此列表:
- 项目已更新(通过 Firebase 在后端)
- 过滤器已更改(每个用户在 Firebase 上单独 table)
- 一个项目已添加书签(每个用户在 Firebase 上单独 table)
为了获取内容列表,我有一个类似这样的函数 return 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
}
}
逻辑很复杂,很难理解。有没有更好的方法来构建它来处理多个不同的变化?存储用户当前过滤器的最佳方式是什么?
谢谢。
我不知道我是否正确地回答了你的问题,但如果你有一个适用于一个列表的视图(类似于 MyItemList
)并且这个列表在几种情况下更新或更改,你必须与 MediatorLiveData
.
我的意思是你必须有三个 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
直到有任何数据改变通知视图。
viewModel
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)
}
});
}
您对 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
。