仅通过当前数据使用MediatorLiveData的最佳实践

时间:2019-01-19 21:59:19

标签: android android-livedata

将MediatorLiveData与多个来源一起使用的最佳做法是什么?

我在ViewModel中有一个MediatorLiveData,可以从视图中访问该数据,最后应该将其显示出来。

MediatorLiveData依赖于其他多个LiveData。其中一些来自存储库层,其中一些必须先在ViewModel中进行处理,然后才能从MediatorLiveData访问它们,而另一些则来自View。

所以我当前的实现类似于以下模式:

public MyViewModel extends ViewModel {
   LiveData<Foo> liveData1;
   LiveData<Bar> liveData2;
   LiveData<FooBar> liveData3;
   //Some other LiveDatas

   MediatorLiveData liveDataForView

   public MyViewModel() {
      liveDataForView = new MediatorLiveData();
      //Do some preprocessing with some of the LiveData
      setupForView();
   }

   public MediatorLiveData getLiveDataForView() {
      return liveDataForView;
   }

   private void setupForView() {
      liveDataForView.addSource(liveData1, (foo -> {
         if(liveData1.getValue() != null && liveData2.getValue() != null && liveData3.getValue() != null /*&& some other LiveData-checks*/)
            liveDataForView.setValue(/*Some combinations of the LiveDatas*/);
      }));
      //Add sources to the MediatorLiveData for any other LiveData
   }
}

我断言,通过此实现,每个LiveData出现后都会设置输出LiveData的值。 在某些情况下,如果我留下一些null-checks,则会收到NullPointerException。 但是这种解决方案对我来说似乎有些混乱,因为对于必须添加到ViewModel的每个LiveData,我都必须将其添加到每个源中。

2 个答案:

答案 0 :(得分:0)

您不必将其添加到每个源的每个表达式中,因为您没有访问lambda表达式中的变量foo。 因此,您可以从所有lambda表达式中调用辅助函数(或者也许甚至可以对所有源重用相同的lambda表达式,无法测试atm。)这样,您只需要在自己的内部定义检查即可单个助手功能。

答案 1 :(得分:0)

首先,您需要一些元组:

public class Tuple2<S, T> {
    public final S first;
    public final T second;

    public Tuple2(S first, T second) {
        this.first = first;
        this.second = second;
    }
}

public class Tuple3<S, T, U> {
    public final S first;
    public final T second;
    public final U third;

    public Tuple3(S first, T second, U third) {
        this.first = first;
        this.second = second;
        this.third = third;
    }
}

public class Tuple4<S, T, U, V> {
    public final S first;
    public final T second;
    public final U third;
    public final V fourth;

    public Tuple4(S first, T second, U third, V fourth) {
        this.first = first;
        this.second = second;
        this.third = third;
        this.fourth = fourth;
    }
}

一旦有了元组,就可以编写类似于Transformations.map的辅助函数,但现在可以:

public class LiveDataTransformations {
    private LiveDataTransformations() {}

    public static <S, T> LiveData<Tuple2<S,T>> ifNotNull(LiveData<S> first, LiveData<T> second) {
        MediatorLiveData<Tuple2<S, T>> mediator = new MediatorLiveData<>();

        mediator.addSource(first, (_first) -> {
            T _second = second.getValue();
            if(_first != null && _second != null) {
                mediator.setValue(new Tuple2(_first, _second));
            }
        });

        mediator.addSource(second, (_second) -> {
            S _first = first.getValue();
            if(_first != null && _second != null) {
                mediator.setValue(new Tuple2(_first, _second));
            }
        });

        return mediator;
    }

    public static <S, T, U> LiveData<Tuple3<S,T,U>> ifNotNull(LiveData<S> first, LiveData<T> second, LiveData<U> third) {
        MediatorLiveData<Tuple3<S, T, U>> mediator = new MediatorLiveData<>();

        mediator.addSource(first, (_first) -> {
            T _second = second.getValue();
            U _third = third.getValue();
            if(_first != null && _second != null && _third != null) {
                mediator.setValue(new Tuple3(_first, _second, _third));
            }
        });

        mediator.addSource(second, (_second) -> {
            S _first = first.getValue();
            U _third = third.getValue();
            if(_first != null && _second != null && _third != null) {
                mediator.setValue(new Tuple3(_first, _second, _third));
            }
        });

        mediator.addSource(third, (_third) -> {
            S _first = first.getValue();
            T _second = second.getValue();
            if(_first != null && _second != null && _third != null) {
                mediator.setValue(new Tuple3(_first, _second, _third));
            }
        });

        return mediator;
    }

    public static <S, T, U, V> LiveData<Tuple4<S,T,U, V>> ifNotNull(LiveData<S> first, LiveData<T> second, LiveData<U> third, LiveData<V> fourth) {
        MediatorLiveData<Tuple4<S, T, U, V>> mediator = new MediatorLiveData<>();

        mediator.addSource(first, (_first) -> {
            T _second = second.getValue();
            U _third = third.getValue();
            V _fourth = fourth.getValue();
            if(_first != null && _second != null && _third != null && _fourth != null) {
                mediator.setValue(new Tuple4(_first, _second, _third, _fourth));
            }
        });

        mediator.addSource(second, (_second) -> {
            S _first = first.getValue();
            U _third = third.getValue();
            V _fourth = fourth.getValue();
            if(_first != null && _second != null && _third != null && _fourth != null) {
                mediator.setValue(new Tuple4(_first, _second, _third, _fourth));
            }
        });

        mediator.addSource(third, (_third) -> {
            S _first = first.getValue();
            T _second = second.getValue();
            V _fourth = fourth.getValue();
            if(_first != null && _second != null && _third != null && _fourth != null) {
                mediator.setValue(new Tuple4(_first, _second, _third, _fourth));
            }
        });

        mediator.addSource(fourth, (_fourth) -> {
            S _first = first.getValue();
            T _second = second.getValue();
            U _third = third.getValue();
            if(_first != null && _second != null && _third != null && _fourth != null) {
                mediator.setValue(new Tuple4(_first, _second, _third, _fourth));
            }
        });

        return mediator;
    }
}

现在您可以做

LiveData<???> liveDataForView;

private void setupForView() {
   LiveData<Tuple3<Foo, Bar, FooBar>> intermediate =  LiveDataTransformations.ifNotNull(liveData1, liveData2, liveData3);
   liveDataForView = Transformations.map(intermediate, (tuple) -> {
       Foo foo = tuple.first;
       Bar bar = tuple.second;
       FooBar fooBar = tuple.third;

       return /*Some combinations of the LiveDatas*/
   });
}