代码之家  ›  专栏  ›  技术社区  ›  Naveed

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

  •  17
  • Naveed  · 技术社区  · 6 年前

    给定以下设置:

    我有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抓取东西等等)

    5 回复  |  直到 6 年前
        1
  •  8
  •   Chrispher    6 年前

    您的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<字符串(>); ,所以现在你的lambda有了意义-它是一个 (String) -> LiveData<String> . 我不得不做另一个改变:使用 switchMap 而不是 map . 这是因为 地图 (X) -> Y 但是 开关映射 需要一个lambda (X) -> LiveData<Y> .

        2
  •  7
  •   Naveed    6 年前

    MediatorLiveData 来解决这个问题。

    MediatorLiveData can观察员其他 LiveData 对象并对其作出反应。

    而不是观察任何一个存储库。我创建了 我的数据 (MediatorLiveData实例)在我的 ViewModel 让我的观点观察这个物体。然后我添加存储库A作为初始源,并观察到这一点,并且只添加 存储库B 如果A的结果需要它。这使我能够保持与每个回购的实时数据相关的转换,并仍然以正确的顺序处理每个结果。执行情况见下文:

    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的情况,但应足够简单,便于处理。

        3
  •  0
  •   imtoori    6 年前

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

        4
  •  0
  •   GilbertS    4 年前

    可以嵌套转换。

    val finalLiveData = Transformations.switchMap(liveData1){
          val search = it
          Transformations.switchMap(liveData2) {
             db(context).dao().all(search, it)
         }
    }
    
        5
  •  -1
  •   amadib    6 年前

    您可以使用 switchmap . 这里有一个例子 documentation .