如何正确组合两个实时数据对象
How to make a combination of two live data objects properly
我有两个相同类型的 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)
}
}
}
我认为这是一个糟糕的方法
您可以使用 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
}
}
}
以上代码将创建一个 MediatorLiveData
具有 2 个源的对象,观察者将计算平方并设置值。
您也可以使用 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
}
}
}
提供的答案是正确的,确实是一个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
}
}
}
我有两个相同类型的 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)
}
}
}
我认为这是一个糟糕的方法
您可以使用 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
}
}
}
以上代码将创建一个 MediatorLiveData
具有 2 个源的对象,观察者将计算平方并设置值。
您也可以使用 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
}
}
}
提供的答案是正确的,确实是一个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
}
}
}