Nav*_*eed 11 android kotlin android-livedata android-architecture-components
鉴于以下设置:
我有2个存储库:存储库A和存储库B它们都返回实时数据.
我有一个使用这两个存储库的ViewModel.
我想从Repository A中提取一些内容,并根据结果我想从Repository B中获取一些东西,然后在返回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()
})
}
})
Run Code Online (Sandbox Code Playgroud)
(另请告诉我是否有替代/推荐的方法来抓取链接这些呼叫的东西,即从A抓取一些东西然后根据A的结果从B中抓取一些东西,依此类推)
你的 lambda 有时返回String "stringA",有时返回LiveData<String>给定的:
Transformations.map(repositoryB.getData(), {
result -> result.toString()
})
Run Code Online (Sandbox Code Playgroud)
这意味着你的 lambda 没有意义——它在不同的分支中返回不同的东西。
正如其他人所提到的,您可以编写自己的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()
})
}
})
Run Code Online (Sandbox Code Playgroud)
我所做的只是让第一个代码分支也返回 a LiveData<String>,所以现在您的 lambda 有意义 - 它是(String) -> LiveData<String>. 我不得不进行另一项更改:使用switchMap而不是map. 这是因为map需要一个 lambda (X) -> Y,但switchMap需要一个 lambda (X) -> LiveData<Y>。
我使用MediatorLiveData解决了此问题。
MediatorLiveData可以观察其他LiveData对象并对它们做出反应。
而不是观察任何一个存储库。我在类中创建了myData(MediatorLiveData的实例),ViewModel并让我的视图观察了该对象。然后,我将存储库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
})
}
})
}
Run Code Online (Sandbox Code Playgroud)
注意:该解决方案并不涵盖可能多次添加repoB的情况,但应足够简单以进行处理。
| 归档时间: |
|
| 查看次数: |
6096 次 |
| 最近记录: |