J'ai actuellement un projet contenant une liste de MyItem
et utilisant Firebase/LiveData. Il est structuré en groupes et chaque groupe a des éléments.
Je souhaite pouvoir mettre à jour cette liste si l'un des événements suivants se produit:
Pour obtenir la liste des contenus, j'ai une fonction comme celle-ci pour retourner LiveData qui se mettra à jour chaque fois qu'un élément est mis à jour (# 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
}
Et dans mon ViewModel, j'ai une logique pour gérer ce cas.
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
}
}
La logique est assez complexe et difficile à suivre. Existe-t-il une meilleure façon de structurer cela pour gérer plusieurs changements différents? Quelle est la meilleure façon de stocker les filtres actuels de l'utilisateur?
Merci.
Je ne sais pas si je reçois votre question correctement ou non, mais si vous avez une vue qui fonctionne avec une liste (quelque chose comme MyItemList
) et cette liste mise à jour ou modifiée par plusieurs situations, vous devez travailler avec MediatorLiveData
.
Je veux dire que vous devez avoir trois LiveData
chacun responsable d'une situation et un MediatorLiveData qui a notifié si chacun d'eux a changé.
voir ci-dessous:
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)
}
Et dans le viewModel
vous avez un MediatorLiveData
qui observe sur ces liveData
s jusqu'à ce que des données aient changé de vue de notification.
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)
}
});
}
Votre implémentation de contents
comprend plusieurs références à des variables externes, ce qui rend difficile le suivi et le suivi de l'état. Je garderais juste les références aussi locales que possible et ferais confiance à switchMap(liveData)
pour faire un bon travail. Le code suivant devrait faire exactement la même chose que le vôtre:
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
}
En ce qui concerne getList(id)
, vous voudrez peut-être également gérer correctement le exception
.