Jetpack介绍之MediatorLiveData

1.介绍

MediatorLiveData是一个LiveData的子类,它将活跃状态或者非活跃状态传播到源LiveData上;也就是说它相当于是一个中间商,通过addSource进行注册的LiveData,当数据进行更新时通过中间商倒一手再进行处理。

2.具体使用

我们看一下官方介绍的两个场景:

  1. 有多个LiveData,我们想要同时监听这两个数据源,只要他们之中有一个数据源更新则接收到通知
    我们看一下具体需要怎么做:
//1.第一个数据源
LiveData liveData1 = ...;
//第二个数据源
LiveData liveData2 = ...;

//2.中间商
MediatorLiveData liveDataMerger = new MediatorLiveData<>();
liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value)//数据源1更新后通知中间商更新);
liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value)//数据源2更新后通知中间商更新);

//3.通过改变数据源1或者2的数据,中间商接收到更新了
liveDataMerger.observe(this, new Observer<String>() {
    @Override
    public void onChanged(String s) {
        Log.i("hellokai", "mediatorLiveData, onChanged:" + s);
    }
});
  1. 如果数据源变化频繁,我们想要只检测前10个数据变化,之后取消数据观察,我们可以用中间商这么做:
liveDataMerger.addSource(liveData1, new Observer() {
    private int count = 1;
    
    @Override public void onChanged(@Nullable Integer s) {
      count++;
      //1.当数据源1更新后,通知中间商进行更新
      liveDataMerger.setValue(s);
      //2.满足条件后,我们进行取消
      if (count > 10) {
          liveDataMerger.removeSource(liveData1);
      }
    }
});

可以看到我们没有影响原数据的注册和解注册,使用中间商倒一手可以灵活实现了!

3.源码分析

这个类总共不到200行代码,比较少,我们具体通过常用方法分析一下如何实现的

3.1来看一下addSource这个方法
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
    //创建了一个新的source对象看3.2
    Source<S> e = new Source<>(source, onChanged);
    Source<?> existing = mSources.putIfAbsent(source, e);
    if (existing != null && existing.mObserver != onChanged) {
        throw new IllegalArgumentException(
                "This source was already added with the different observer");
    }
    if (existing != null) {
        return;
    }
    //如果这个中间商之前通过数据更新,则在此进行注册,防止在onChanged数据解绑定再注册没有注册的问题
    if (hasActiveObservers()) {
        e.plug();
    }
}
3.2来看一下Source这个类
//继承自observer
private static class Source<V> implements Observer<V> {
    final LiveData<V> mLiveData;
    final Observer<? super V> mObserver;
    int mVersion = START_VERSION;

    Source(LiveData<V> liveData, final Observer<? super V> observer) {
        mLiveData = liveData;
        mObserver = observer;
    }

    void plug() {
        //mLiveData注册一直是active状态,直到调用removeObserver
        mLiveData.observeForever(this);
    }

    void unplug() {
        mLiveData.removeObserver(this);
    }

    @Override
    public void onChanged(@Nullable V v) {
        //将当前的mVersion和mLiveData.getVersion()进行绑定
        if (mVersion != mLiveData.getVersion()) {
            mVersion = mLiveData.getVersion();
            mObserver.onChanged(v);
        }
    }
}
3.3既然是LiveData的子类,再看一下onActive()onInactive()这两个方法
@CallSuper
@Override
protected void onActive() {
    for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
        source.getValue().plug();
    }
}

@CallSuper
@Override
protected void onInactive() {
    for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
        source.getValue().unplug();
    }
}

我们可以知道了mSources是在调用addSource()方法时绑定的数据源,当此中介者处于活跃状态时,进行注册和数据分发处理,如果是非活跃状态,也进行解注册。

4.Transformations使用分析

map()switchMap()方法使用到了MediatorLiveData这个类,使用同RxJava中的map()flatmap()方法使用是类似的;我们也来分析一下它的具体作用

public static <X, Y> LiveData<Y> map(
            @NonNull LiveData<X> source,
            @NonNull final Function<X, Y> mapFunction) {
    final MediatorLiveData<Y> result = new MediatorLiveData<>();
    result.addSource(source, new Observer<X>() {
        @Override
        public void onChanged(@Nullable X x) {
            result.setValue(mapFunction.apply(x));
        }
    });
    return result;
}

可以看到,使用了中间商MediatorLiveData,绑定了源数据,当源数据改变的时候会用此Function来进行通知
我们再来看一下switchMap()这个方法:

public static <X, Y> LiveData<Y> switchMap(
            @NonNull LiveData<X> source,
            @NonNull final Function<X, LiveData<Y>> switchMapFunction) {
    final MediatorLiveData<Y> result = new MediatorLiveData<>();
    result.addSource(source, new Observer<X>() {
        LiveData<Y> mSource;

        @Override
        public void onChanged(@Nullable X x) {
            //1.获取到LiveData
            LiveData<Y> newLiveData = switchMapFunction.apply(x);
            //2.判断LiveData是否是新的,如果不是新的则返回
            if (mSource == newLiveData) {
                return;
            }
            //3.如果是新的,则先解注册
            if (mSource != null) {
                result.removeSource(mSource);
            }
            mSource = newLiveData;
            if (mSource != null) {
                //4.再将新的LiveData进行注册
                result.addSource(mSource, new Observer<Y>() {
                    @Override
                    public void onChanged(@Nullable Y y) {
                        result.setValue(y);
                    }
                });
            }
        }
    });
    return result;
}

那它的具体使用场景是什么呢?我们来看一下如果我们在ViewModel中直接返回了RepositoryLiveData那么因为Repository产生的LiveData每次返回的都是一个新的LiveData,这样如果不重新解注册之前的,重新注册新的就会有问题,这个时候我们就可以使用switchMap来做了,通过源码分析我们看到了,它会解注册之前的再注册新的LiveData

我们以官方文档中的例子再具体分析一下:

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    public MyViewModel(PostalCodeRepository repository) {
       this.repository = repository;
    }

    private LiveData<String> getPostalCode(String address) {
       // 无论是通过网络retrofit还是走数据库都是返回的新的LiveData,直接返回的话,相当于每次都是重新注册的一个新的LiveData,没有必要
       return repository.getPostCode(address);
    }
}

可以使用switchMap()来做一个转换进行处理:

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    private final MutableLiveData<String> addressInput = new MutableLiveData();
    //1.使用switchMap来保证只注册一个LiveData
    public final LiveData<String> postalCode =
            Transformations.switchMap(addressInput, (address) -> {
                return repository.getPostCode(address);
             });

  public MyViewModel(PostalCodeRepository repository) {
      this.repository = repository
  }

  //2.外部通过设置此方法来进行更新
  private void setInput(String address) {
      addressInput.setValue(address);
  }
}

以上我们就清楚了它的使用场景了!

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值