【Jetpack】LiveData一些容易被忽视的功能

1,199 阅读2分钟

前言

LiveData平时经常使用,但是仅限于在页面上oberver注册一个观察者,在ViewModel里调用一下setValue、postValue仅此而已,今天决定过一遍LiveData库,发现了几个不常用但是却很有用的东西。

LiveData核心库有两个:lifecycle-livedatalifecycle-livedata-core

微信截图_20220513101852.png

LiveData.java

这是LiveData的核心类,所有主要逻辑均位于此

在这里发现了这个observeForever,这个方法很少用,调用此方法注册的观察者,将始终处于激活状态,页面Pause、Destroy状态对他无效,所以不用的时候需要手动调用removeObserver。有些时候需要我们在页面处于Pause状态时,也能收到LiveData发送的数据,那observeForever就派上用场了。

public void observeForever(@NonNull Observer<? super T> observer) {
   ...
}

@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
    ...
}

@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner) {
    ...
    一步移除页面上所有观察者
}

MediatorLiveData.java

  • MediatorLiveData.addSource 通过addSource可以添加多个LiveData源进来,只要其中有一个发射数据,MediatorLiveData就会触发并转发这个数据,当我们需要观察多个源时,可以考虑一下,能否用MediatorLiveData收拢成一个发射源
  • MediatorLiveData.removeSource 随时可以删除已经添加过的输入源
   LiveData  liveData1 = ...;
   LiveData  liveData2 = ...;
  
   MediatorLiveData  liveDataMerger = new MediatorLiveData<>();
   liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
   liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
   
@MainThread
public <S> void removeSource(@NonNull LiveData<S> toRemote) {
    Source<?> source = mSources.remove(toRemote);
    if (source != null) {
        source.unplug();
    }
}   

Transformations.java

  • Transformations.distinctUntilChanged 经过distinctUntilChanged处理过的LiveData 遇到连续多次发射同一个值时,将自动拦截屏蔽和上一次发射值重复的值,去重防抖动利器
   MutableLiveData source = new MutableLiveData<Integer>()
   MutableLiveData outputSource = Transformations.distinctUntilChanged(source)
  • Transformations.map 根据指定的Function,可以将原始的LiveData的发射值类型,转换成另一个类型的LiveData
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;
}
  • Transformations.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) {
            LiveData<Y> newLiveData = switchMapFunction.apply(x);
            if (mSource == newLiveData) {
                return;
            }
            if (mSource != null) {
                result.removeSource(mSource);
            }
            mSource = newLiveData;
            if (mSource != null) {
                result.addSource(mSource, new Observer<Y>() {
                    @Override
                    public void onChanged(@Nullable Y y) {
                        result.setValue(y);
                    }
                });
            }
        }
    });
    return result;
}
class UserViewModel extends AndroidViewModel {
    MutableLiveData<String> nameQueryLiveData = ...

    LiveData<List<String>> getUsersWithNameLiveData() {
        return Transformations.switchMap(
            nameQueryLiveData,
                name -> myDataSource.getUsersWithNameLiveData(name));
    }

    void setNameQuery(String name) {
        this.nameQueryLiveData.setValue(name);
    }
}