如何在使用实时数据时链接Android中的转换?

时间:2017-11-12 20:18:16

标签: android kotlin android-architecture-components android-livedata

给出以下设置:

我有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()
                })
            }
        })

(另请告诉我是否有替代/推荐的方法来抓取链接这些电话的东西,即从A中抓取一些东西,然后根据A的结果从B中抓取一些东西等等)

4 个答案:

答案 0 :(得分:5)

我用MediatorLiveData来解决这个问题。

MediatorLiveData可以观察其他LiveData个对象并做出反应。

而不是观察任何一个存储库。我在ViewModel类中创建了 myData (MediatorLiveData的实例)并让我的视图观察到这个对象。然后我添加Repository 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的情况,但它应该足够简单,可以处理。

答案 1 :(得分:4)

您的lambda有时返回String "stringA",有时返回由以下内容提供的LiveData<String>

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

这意味着您的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()
            })
        }
    })

我所做的只是使第一个代码分支也返回一个LiveData<String>,所以现在您的lambda才有意义-它是一个(String) -> LiveData<String>。我还必须进行其他更改:使用switchMap而不是map。这是因为map的值是(X) -> Y,而switchMap的值是(X) -> LiveData<Y>

答案 2 :(得分:0)

我会尝试使用switchMap而不是map:

  

与map()类似,将函数应用于存储在LiveData对象中的值,并将结果解包并调度到下游。传递给switchMap()的函数必须返回一个LiveData对象。

答案 3 :(得分:0)

您可以嵌套转换。

Vec<_>