次の設定を前提とします。
Repository AとRepository 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()
})
}
})
(また、これらの呼び出しをチェーンするために何かをつかむための代替/推奨されるアプローチがあるかどうかを教えてください。
この問題を解決するために 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が複数回追加される可能性がある場合をカバーしていませんが、処理するのに十分単純である必要があります。
ラムダは時々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>
を取るためです。
変換をネストできます。
val finalLiveData = Transformations.switchMap(liveData1){
val search = it
Transformations.switchMap(liveData2) {
db(context).dao().all(search, it)
}
}
私はマップの代わりにswitchMapを使用してみます:
Map()と同様に、LiveDataオブジェクトに格納されている値に関数を適用し、結果をアンラップしてダウンストリームにディスパッチします。 switchMap()に渡される関数は、LiveDataオブジェクトを返す必要があります。
switchmap
を使用してデータを変換できます。以下に例を示します documentation 。