前言
LiveData的优势以及实现原理已经在上一篇中介绍,那么接下来接触一些扩展用法,从而更能体会该组件的设计意图,方便在业务中进行相应的扩展。
扩展LiveData
以下为股票价格监听StockLiveData,只有观察者生命周期处于STARTED或者RESUMED状态,则LiveData会认为观察者处于活跃状态,再进行相关连接操作,更新股价信息。这种实现规则与MediatorLiveData类似。
public class StockLiveData extends LiveData<BigDecimal> {
private StockManager stockManager;
private SimplePriceListener listener = new SimplePriceListener() {
@Override
public void onPriceChanged(BigDecimal price) {
//更新值,并将更改通知给任何活跃观察者
setValue(price);
}
};
public StockLiveData(String symbol) {
stockManager = new StockManager(symbol);
}
//当StockLiveData有活跃对象时,会调用该方法。从而开始观察股价更新
@Override
protected void onActive() {
stockManager.requestPriceUpdates(listener);
}
//当StockLiveData没有任何活跃观察者时,会调用该方法。由于没有观察者在监听,因此没有理由与StockManager服务保持连接
@Override
protected void onInactive() {
stockManager.removeUpdates(listener);
}
}
可在UI控制器中进行如下调用:
public class MyFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
LiveData<BigDecimal> myPriceListener = ...;
myPriceListener.observe(getViewLifeycleOwner(), price -> {
// Update the UI.
});
}
}
LiveData对象具有生命周期感知能力,意味着可以在多个Activity和Fragment之间共享这些对象,从而保证各个Activity或者Fragment随时拿到的值都是最新的值。为了达到共享,可以将LiveData设置为单一实例,如下所示:
public class StockLiveData extends LiveData<BigDecimal> {
private static StockLiveData sInstance;
private StockManager stockManager;
private SimplePriceListener listener = new SimplePriceListener() {
@Override
public void onPriceChanged(BigDecimal price) {
setValue(price);
}
};
@MainThread
public static StockLiveData get(String symbol) {
if (sInstance == null) {
sInstance = new StockLiveData(symbol);
}
return sInstance;
}
private StockLiveData(String symbol) {
stockManager = new StockManager(symbol);
}
@Override
protected void onActive() {
stockManager.requestPriceUpdates(listener);
}
@Override
protected void onInactive() {
stockManager.removeUpdates(listener);
}
}
可在不同的Fragment中使用,如下所示:
public class MyFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {
// Update the UI.
});
}
}
public class PriceFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {
// Update the UI.
});
}
}
多个 Fragment 和 Activity 可以观察 MyPriceListener 实例。仅当一个或多个系统服务可见且处于活跃状态时,LiveData 才会连接到该服务。
LiveData-MediatorLiveData
MediatorLiveData,LiveData的子类,可观察指定LiveData对象,当其数据发生变化时,有且只有该MediatorLiveData有活跃观察者时,才会通知onChanged方法。接下来分析其实现原理:
public class MediatorLiveData<T> extends MutableLiveData<T> {
//一个LiveData 对一个Source对象。
private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();
//为目标LiveData添加Observer,当LiveData数据发生变化时,回调指定的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;
}
//添加Observer
void plug() {
mLiveData.observeForever(this);
}
//移除Observer
void unplug() {
mLiveData.removeObserver(this);
}
@Override
public void onChanged(@Nullable V v) {
if (mVersion != mLiveData.getVersion()) {
mVersion = mLiveData.getVersion();
mObserver.onChanged(v);
}
}
}
//添加source对象以及观察则Observer
@MainThread
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
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;
}
if (hasActiveObservers()) {
e.plug();
}
}
//下面这个两个方法非常重要,只有当前MediatorLiveData有活跃观察者时,LiveData的数据变化,addSource添加的onChanged 才会执行。
@CallSuper
@Override
protected void onActive() {
for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
source.getValue().plug();
}
}
//当前MediatorLiveData没有任何活跃观察者,会移除对对sourc LiveData的监听
@CallSuper
@Override
protected void onInactive() {
for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
source.getValue().unplug();
}
}
MediatorLiveData也是一个LiveData,在使用的时候,需要调用observe或者observeForever添加观察者,这样当input LiveData的数据发生变化是,onChanged方法才会执行。
下面测试他的使用:
public void onClick(View view) {
if (view.getId() == R.id.btn_first) {
liveData1.setValue(100+random.nextInt(10));
} else if (view.getId() == R.id.btn_second) {
liveData2.setValue(200+random.nextInt(10));
}
}
// new liveData
MediatorLiveData<Integer> liveDataMerger = new MediatorLiveData<>();
//input liveData
MutableLiveData<Integer> liveData1 = new MutableLiveData<>();
MutableLiveData<Integer> liveData2 = new MutableLiveData<>();
private void initMediator(){
liveDataMerger.addSource(liveData1, new Observer<Integer>() {
int count;
@Override
public void onChanged(Integer integer) {
count++;
liveDataMerger.setValue(integer);
//大于10次后移除对liveData1的监听
if(count > 10){
liveDataMerger.removeSource(liveData1);
}
}
});
liveDataMerger.addSource(liveData2, new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
liveDataMerger.setValue(integer);
}
});
//如果不为liveDataMerger添加观察者,即使liveData1或者liveData2的数据发生改变,addSource()方法的onChanged观察不会受到回调,以为不处于当前liveDataMerger不处于active状态,不会调用Source的plug()方法,为liveData1或者liveData2添加观察者
liveDataMerger.observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
showToast("liveDataMerger data changed:"+integer.toString());
}
});
}
private void showToast(String msg){
Toast.makeText(getApplicationContext(),msg,Toast.LENGTH_SHORT).show();
}
Transformations 对LiveData进行转换处理
1,map
map对inputData的数据通过mapFunction处理,得到新的类型数据,并返回一个对应的LiveData。功能和RxJava的map操作符类似。其实现主要是借助MediatorLiveData实现的中转;
@MainThread
public static <X, Y> LiveData<Y> map(
@NonNull LiveData<X> source,
@NonNull final Function<X, Y> mapFunction) {
//返回的新LiveData对象
final MediatorLiveData<Y> result = new MediatorLiveData<>();
//添加观察,当source数据发生变化时,调用onChaged方法,再调用mapFunction对数据按照要求进行映射处理
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(mapFunction.apply(x));
}
});
return result;
}
使用示例:
private MutableLiveData<Integer> source = new MutableLiveData<Integer>();
private void testMap(){
Transformations.map(source, new Function<Integer, String>() {
@Override
public String apply(Integer input) {
return "changed data "+input.toString();
}
}).observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
showToast(s);
}
});
}
1,switchMap
switchMap也是拿来做数据转换处理的,当source数据变化时,回调onChagned方法,再执行switchMapFunction,这里返回的是LiveData对象,再次监听新的LiveData数据变化,最后将值设置给result;
@MainThread
public static <X, Y> LiveData<Y> switchMap(
@NonNull LiveData<X> source,
@NonNull final Function<X, LiveData<Y>> switchMapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
//监听srouce数据变化
result.addSource(source, new Observer<X>() {
LiveData<Y> mSource;
@Override
public void onChanged(@Nullable X x) {
//当source数据变化时,拿到对应的值,再由switchMapFunction进行处理
LiveData<Y> newLiveData = switchMapFunction.apply(x);
if (mSource == newLiveData) {
return;
}
if (mSource != null) {
result.removeSource(mSource);
}
mSource = newLiveData;
if (mSource != null) {
//对switchMapFunction返回的LiveData对象进行数据监听
result.addSource(mSource, new Observer<Y>() {
@Override
public void onChanged(@Nullable Y y) {
//最终将值设置给result
result.setValue(y);
}
});
}
}
});
return result;
}
使用示例:
class UserViewModel extends AndroidViewModel {
MutableLiveData<String> nameQueryLiveData = new MutableLiveData<>();
public LiveData<List<String>> getUsersWithNameLiveData() {
return Transformations.switchMap(
nameQueryLiveData,
name -> myDataSource.getUsersWithNameLiveData(name));
}
public void setNameQuery(String name) {
this.nameQueryLiveData.setValue(name);
}
}
switchMap的使用场景在ViewModel中经常使用,比如当调用myDataSource从网络或者room返回LiveData数据时,需要结合switchMap进行处理,最终将值回调给Fragment或者Activity进行处理。