現在、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
}
}
ロジックはかなり複雑で、理解するのが難しいです。これを構造化して複数の異なる変更を処理するより良い方法はありますか?ユーザーの現在のフィルターを保存する最良の方法は何ですか?
ありがとう。
私はあなたの質問が正しく得られるかどうかわかりませんが、1つのリスト(MyItemList
など)で機能するビューがあり、このリストがいくつかの状況で更新または変更される場合、MediatorLiveData
で作業する必要があります。
つまり、状況に責任を持つ3つのLiveData
と、それぞれが変更されたかどうかを通知する1つの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
sを監視するliveData
が1つあります。
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
を適切に処理することもできます。