使用实时数据时如何在 Android 中链接转换?
How to chain transformations in Android when using live data?
给定以下设置:
我有 2 个存储库:存储库 A 和 存储库 B 它们都是 return 实时数据。
我有一个使用这两个存储库的 ViewModel。
我想从存储库 A 中提取一些内容,根据结果,我想从存储库 B 中提取一些内容,然后在 returning 之前将结果转换为 UI。
为此,我一直在查看 LiveData Transformation 类。这些示例显示了结果的单一转换,但是我想要一些类似于链接两个转换的东西。我怎样才能做到这一点?
我试过这样设置,但在第二个转换块上出现类型不匹配:
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()
})
}
})
(另外请让我知道是否有一种 alternate/recommended 方法来获取链接这些调用的内容,即从 A 获取内容,然后根据 A 的结果从 B 获取内容等等)
我会尝试使用 switchMap 而不是 map:
Similar to map(), applies a function to the value stored in the LiveData object and unwraps and dispatches the result downstream. The function passed to switchMap() must return a LiveData object.
您可以使用 switchmap
转换数据。这是一个示例 documentation.
我用MediatorLiveData解决了这个问题。
MediatorLiveData 可以观察其他 LiveData
对象并对它们做出反应。
而不是观察任何一个存储库。我在我的 ViewModel
class 中创建了 myData(MediatorLiveData 的实例)并让我的视图观察这个对象。然后我将存储库 A 添加为初始源并观察它,并且仅在 A 的结果需要时才添加 Repository B。这使我能够保持与每个 repo 的实时数据关联的转换,并且仍然以正确的顺序处理每个结果。实施见下文:
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可能被多次添加的情况,但应该足够简单处理。
您的 lambda 有时 return 是 String
"stringA"
,有时 return 是 LiveData<String>
给出的:
Transformations.map(repositoryB.getData(), {
result -> result.toString()
})
这意味着您的 lambda 没有意义 - 它 return 在不同的分支中有不同的东西。
正如其他人所提到的,您 可以 编写自己的 MediatorLiveData
而不是使用 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()
})
}
})
我所做的就是使第一个代码分支也 return 成为 LiveData<String>
,所以现在您的 lambda 变得有意义了 - 它是 (String) -> LiveData<String>
。我不得不进行另一项更改:使用 switchMap
而不是 map
。这是因为 map
采用 lambda (X) -> Y
,但 switchMap
采用 lambda (X) -> LiveData<Y>
.
您可以嵌套转换。
val finalLiveData = Transformations.switchMap(liveData1){
val search = it
Transformations.switchMap(liveData2) {
db(context).dao().all(search, it)
}
}
给定以下设置:
我有 2 个存储库:存储库 A 和 存储库 B 它们都是 return 实时数据。
我有一个使用这两个存储库的 ViewModel。
我想从存储库 A 中提取一些内容,根据结果,我想从存储库 B 中提取一些内容,然后在 returning 之前将结果转换为 UI。
为此,我一直在查看 LiveData Transformation 类。这些示例显示了结果的单一转换,但是我想要一些类似于链接两个转换的东西。我怎样才能做到这一点?
我试过这样设置,但在第二个转换块上出现类型不匹配:
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()
})
}
})
(另外请让我知道是否有一种 alternate/recommended 方法来获取链接这些调用的内容,即从 A 获取内容,然后根据 A 的结果从 B 获取内容等等)
我会尝试使用 switchMap 而不是 map:
Similar to map(), applies a function to the value stored in the LiveData object and unwraps and dispatches the result downstream. The function passed to switchMap() must return a LiveData object.
您可以使用 switchmap
转换数据。这是一个示例 documentation.
我用MediatorLiveData解决了这个问题。
MediatorLiveData 可以观察其他 LiveData
对象并对它们做出反应。
而不是观察任何一个存储库。我在我的 ViewModel
class 中创建了 myData(MediatorLiveData 的实例)并让我的视图观察这个对象。然后我将存储库 A 添加为初始源并观察它,并且仅在 A 的结果需要时才添加 Repository B。这使我能够保持与每个 repo 的实时数据关联的转换,并且仍然以正确的顺序处理每个结果。实施见下文:
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可能被多次添加的情况,但应该足够简单处理。
您的 lambda 有时 return 是 String
"stringA"
,有时 return 是 LiveData<String>
给出的:
Transformations.map(repositoryB.getData(), {
result -> result.toString()
})
这意味着您的 lambda 没有意义 - 它 return 在不同的分支中有不同的东西。
正如其他人所提到的,您 可以 编写自己的 MediatorLiveData
而不是使用 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()
})
}
})
我所做的就是使第一个代码分支也 return 成为 LiveData<String>
,所以现在您的 lambda 变得有意义了 - 它是 (String) -> LiveData<String>
。我不得不进行另一项更改:使用 switchMap
而不是 map
。这是因为 map
采用 lambda (X) -> Y
,但 switchMap
采用 lambda (X) -> LiveData<Y>
.
您可以嵌套转换。
val finalLiveData = Transformations.switchMap(liveData1){
val search = it
Transformations.switchMap(liveData2) {
db(context).dao().all(search, it)
}
}