В настоящее время у меня есть проект, который содержит список MyItem
и использует Firebase/LiveData. Он структурирован по группам, и в каждой группе есть элементы.
Я хочу иметь возможность обновлять этот список, если произойдет одно из следующих событий:
Чтобы получить список содержимого, у меня есть подобная функция для возврата 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
, пока какие-либо данные не изменятся, не уведомите представление.
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)
}
});
}
@Advice-Dog в разделе addSource
вы можете добавить любую логику, которая настраивает ваш список. см. мой отредактированный ответ.
Ваша реализация 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
.
getFilteredData()
иgetBookmarkedList()
не возвращают списокMyItem
, они возвращают разные объекты, такие какFilter
для поиска, поэтому я не могу просто установить значениеresult
вViewModel
. Я думаю, мне нужно либо кэшировать весь список изgetListFromServer()
, либо мне нужно снова сделать этот вызов после получения новогоFilter
.