web-dev-qa-db-ja.com

さまざまなタイプの複数のソースを持つLiveData

現在、MyItemのリストを含むプロジェクトがあり、Firebase/LiveDataを使用しています。グループ化されており、各グループにはアイテムがあります。

次のいずれかが発生した場合、このリストを更新できるようにしたいと思います。

  1. アイテムが更新されました(Firebaseを介してバックエンドで)
  2. フィルターが変更された(Firebaseのユーザーごとに個別のテーブル)
  3. アイテムがブックマークされている(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
        }
    }

ロジックはかなり複雑で、理解するのが難しいです。これを構造化して複数の異なる変更を処理するより良い方法はありますか?ユーザーの現在のフィルターを保存する最良の方法は何ですか?

ありがとう。

7
Advice-Dog

私はあなたの質問が正しく得られるかどうかわかりませんが、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には、データが通知ビューを変更したかどうかまでこれらのMediatorLiveDatasを監視するliveDataが1つあります。

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)
        }
   });

}
1
SamiAzar

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を適切に処理することもできます。

1
tynn