web-dev-qa-db-ja.com

Androidでライブ変換を使用するときに変換をチェーンする方法は?

次の設定を前提とします。

Repository ARepository Bの2つのリポジトリが返されますライブデータ。

これらのリポジトリの両方を使用するViewModelがあります。

リポジトリAから何かを抽出し、結果に応じてリポジトリBから何かを取得し、UIに戻る前に結果を変換したい。

このため、私は LiveData Transformation クラスを調べてきました。例では、結果の単一の変換を示していますが、2つの変換を連鎖させることで何かが必要です。どうすればこれを達成できますか?

私はこのようなものを設定しようとしましたが、2番目の変換ブロックで型の不一致が発生します。

  internal val launchStatus: LiveData<String> = Transformations
        .map(respositoryA.getData(), { data ->
            if (data.isValid){
                "stringA"
            } else {
                //This gives a type mismatch for the entire block
                Transformations.map(repositoryB.getData(), {
                    result -> result.toString()
                })
            }
        })

(また、これらの呼び出しをチェーンするために何かをつかむための代替/推奨されるアプローチがあるかどうかを教えてください。

11
Naveed

この問題を解決するために MediatorLiveData を使用しました。

MediatorLiveData は他のLiveDataオブジェクトを監視し、それらに反応できます。

どちらかのリポジトリを監視する代わりに。 ViewModelクラスにmyData(MediatorLiveDataのインスタンス)を作成し、ビューにこのオブジェクトを監視させました。次に、リポジトリAを初期ソースとして追加し、それを観察して、Aの結果で必要な場合にのみリポジトリBを追加します。これにより、各リポジトリのライブデータに関連付けられた変換を維持しながら、各結果を正しい順序で処理できます。実装については以下を参照してください:

internal val myData: MediatorLiveData<String> = MediatorLiveData()

private val repoA: LiveData<String> = Transformations.map(
        respositoryA.getData(), { data ->
    if (data.isValid) "stringA" else ""

})

private val repoB: LiveData<String> = Transformations.map(
        repositoryB.getData(), { data -> "stringB" 
})

fun start() {
    myData.addSource(repoA, {
        if (it == "stringA") {
            myData.value = it
        } else {
            myData.addSource(repoB, {
                myData.value = it
            })
        }
    })
}

:このソリューションは、repoBが複数回追加される可能性がある場合をカバーしていませんが、処理するのに十分単純である必要があります。

5
Naveed

ラムダは時々String"stringA"を返し、時々LiveData<String>を返します:

Transformations.map(repositoryB.getData(), {
    result -> result.toString()
})

これは、ラムダが意味をなさないことを意味します-異なるブランチで異なるものを返します。

他の人が述べたように、あなたはcouldMediatorLiveDataで指定されたものを使用する代わりに、独自のTransformationsを記述します。ただし、次の方法の方が簡単だと思います。

internal val launchStatus: LiveData<String> = Transformations
    .switchMap(respositoryA.getData(), { data ->
        if (data.isValid) {
            MutableLiveData().apply { setValue("stringA") }
        } else {
            Transformations.map(repositoryB.getData(), {
                result -> result.toString()
            })
        }
    })

最初に行ったコードブランチでもLiveData<String>が返されるようにしたので、ラムダは意味を成します。これは(String) -> LiveData<String>です。もう1つ変更を加える必要がありました。switchMapではなくmapを使用してください。これは、mapがラムダ(X) -> Yを取るのに対し、switchMapはラムダ(X) -> LiveData<Y>を取るためです。

4
Chrispher

変換をネストできます。

val finalLiveData = Transformations.switchMap(liveData1){
      val search = it
      Transformations.switchMap(liveData2) {
         db(context).dao().all(search, it)
     }
}
0
GilbertS

私はマップの代わりにswitchMapを使用してみます:

Map()と同様に、LiveDataオブジェクトに格納されている値に関数を適用し、結果をアンラップしてダウンストリームにディスパッチします。 switchMap()に渡される関数は、LiveDataオブジェクトを返す必要があります。

0

switchmapを使用してデータを変換できます。以下に例を示します documentation

0
Ben Lewis