仅通过当前数据使用 MediatorLiveData 的最佳实践
Best practice for using MediatorLiveData only by present data
将 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 存在之后设置的。
在某些情况下,如果我遗漏了一些空检查,我会得到一个 NullPointerException。
但是这个解决方案对我来说似乎有点混乱,因为对于我必须添加到 ViewModel 的每个 LiveData,我都必须将它添加到每个源中。
您不必将它添加到每个来源的每个表达式中,因为您没有访问 lambda 表达式中的变量 foo。
因此,您可以从所有 lambda 表达式中调用辅助函数(或者您甚至可以对所有源重复使用相同的 lambda 表达式,无法测试该 atm。),这样您只需要在您的内部定义检查单个辅助函数。
首先你需要一些元组:
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*/
});
}
编辑: 您可以使用库 https://github.com/Zhuinden/livedata-combinetuple-kt 做同样的事情。
将 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 存在之后设置的。 在某些情况下,如果我遗漏了一些空检查,我会得到一个 NullPointerException。 但是这个解决方案对我来说似乎有点混乱,因为对于我必须添加到 ViewModel 的每个 LiveData,我都必须将它添加到每个源中。
您不必将它添加到每个来源的每个表达式中,因为您没有访问 lambda 表达式中的变量 foo。 因此,您可以从所有 lambda 表达式中调用辅助函数(或者您甚至可以对所有源重复使用相同的 lambda 表达式,无法测试该 atm。),这样您只需要在您的内部定义检查单个辅助函数。
首先你需要一些元组:
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*/
});
}
编辑: 您可以使用库 https://github.com/Zhuinden/livedata-combinetuple-kt 做同样的事情。