17

鉴于以下设置:

我有 2 个存储库:存储库 A存储库 B,它们都返回实时数据。

我有一个使用这两个存储库的 ViewModel。

我想从存储库 A 中提取一些东西,根据结果我想从存储库 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

5 回答 5

8

您的 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()
            })
        }
    })

我所做的只是让第一个代码分支也返回 a LiveData<String>,所以现在你的 lambda 是有意义的——它是 a (String) -> LiveData<String>。我不得不做出另一项改变:使用switchMap而不是map. 这是因为map需要一个 lambda (X) -> Y,但switchMap需要一个 lambda (X) -> LiveData<Y>

于 2018-10-11T15:56:40.427 回答
7

我使用MediatorLiveData来解决这个问题。

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

而不是观察任何一个存储库。我在课堂上创建了myData(MediatorLiveData 的实例)ViewModel并让我的视图观察这个对象。然后我将存储库 A 添加为初始源并观察它,并且仅在A 的结果需要时才添加存储库 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 的情况,但它应该足够简单以便处理。

于 2017-12-11T22:43:25.250 回答
0

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

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

于 2017-11-12T20:49:29.930 回答
0

您可以嵌套转换。

val finalLiveData = Transformations.switchMap(liveData1){
      val search = it
      Transformations.switchMap(liveData2) {
         db(context).dao().all(search, it)
     }
}
于 2020-01-30T19:38:38.350 回答
-1

您可以使用 转换数据switchmap。这是一个示例文档

于 2017-11-27T18:03:39.163 回答