【问题标题】:How to make a combination of two live data objects properly如何正确组合两个实时数据对象
【发布时间】:2021-02-10 10:22:54
【问题描述】:

我有两个相同类型的 LiveData 对象,我想对输出进行相同的计算。像 Rx 中的合并运算符之类的东西我怎么能做到这一点。目前我正在这样做:

class VM : ViewModel() {
    val input1LiveData = MutableLiveData<Int>()
    val input2LiveData = MutableLiveData<Int>()
    val squareLiveData = MutableLiveData<Int>()
}

class MyFragment : Fragment() {
    private void fillSquare(input: Int){
        viewmodel.squareLiveData.value = input * input
    }
    override onViewCreated(){
        viewmodel.input1LiveData.observe(viewLifecycleOwner){
            fillSquare(it * it)
        }
        viewmodel.input2LiveData.observe(viewLifecycleOwner){
            fillSquare(it * it)
        }
    }
}

我猜这是一个不好的方法

【问题讨论】:

    标签: android kotlin android-livedata


    【解决方案1】:

    您可以使用MediatorLiveData,它是一种特殊类型的 LiveData,能够连接到其他 liveData 对象作为源。您可以像这样改进上面的代码:

    class VM : ViewModel() {
        val input1LiveData = MutableLiveData<Int>()
        val input2LiveData = MutableLiveData<Int>()
        
        val squareLiveData = MediatorLiveData<Int>().apply{
            val observer = Observer<T> { value = it*it }
            addSource(input1LiveData, observer)
            addSource(input2LiveData, observer)
        }
    }
    
    class MyFragment : Fragment() {
        override onViewCreated(){
            viewmodel.squareLiveData.observe(viewLifecycleOwner){
                //do your ui updates
            }
        }
    }
    

    上面的代码将创建一个有 2 个源的 MediatorLiveData 对象,观察者将计算平方并设置值。


    您也可以使用ReactiveLiveData 库,通过反应式方法来实现这一点,使代码更易于编写和阅读:D 就像这样。

    class VM : ViewModel() {
        val input1LiveData = MutableLiveData<Int>()
        val input2LiveData = MutableLiveData<Int>()
    
        val squareLiveData = input1LiveData.merge(input2LiveData).map{it*it}
    }
    
    class MyFragment : Fragment() {
        override onViewCreated(){
            viewmodel.squareLiveData.observe(viewLifecycleOwner){
                //do your ui updates
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      提供的答案是正确的,确实是可以解决这个问题的MediatorLiveData,例如:

      public class CombinedLiveData2<A, B> extends MediatorLiveData<Pair<A, B>> {
          private A a;
          private B b;
      
          public CombinedLiveData2(LiveData<A> ld1, LiveData<B> ld2) {
              setValue(Pair.create(a, b));
      
              addSource(ld1, (a) -> { 
                   if(a != null) {
                      this.a = a;
                   } 
                   setValue(Pair.create(a, b)); 
              });
      
              addSource(ld2, (b) -> { 
                  if(b != null) {
                      this.b = b;
                  } 
                  setValue(Pair.create(a, b));
              });
          }
      }
      

      如果您想为更多 LiveData 执行此操作,可以使用 https://github.com/Zhuinden/livedata-combinetuple-kt/

      class VM : ViewModel() {
          val input1LiveData = MutableLiveData<Int>(0)
          val input2LiveData = MutableLiveData<Int>(0)
          val squareLiveData = combineTupleNonNull(input1LiveData, input2LiveData)
                                   .map { (input1, input2) -> 
                                       /* do transform */
                                   }
      }
      
      class MyFragment : Fragment() {
          override onViewCreated(view: View, savedInstanceState: Bundle?) {
              super.onViewCreated(view, savedInstanceState)    
      
              viewmodel.squareLiveData.observe(viewLifecycleOwner) {
                  // do something with square value
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2021-02-17
        • 2021-09-12
        • 2022-01-04
        • 2019-07-21
        • 2021-02-02
        • 1970-01-01
        • 2015-08-06
        相关资源
        最近更新 更多