[Jetpack] Some easily overlooked features of LiveData

foreword

LiveData is often used, but it is limited to registering an observer on the page, calling setValue and postValue in the ViewModel and that's all. Today, I decided to go through the LiveData library and found a few things that are not commonly used but very useful.

There are two LiveData core libraries: lifecycle-livedata and lifecycle-livedata-core

WeChat screenshot_20220513101852.png

LiveData.java

This is the core class of LiveData, all the main logic is located here

I found this observeForever here . This method is rarely used. The observer registered by calling this method will always be in an active state. The Pause and Destroy states of the page are invalid for him, so you need to manually call removeObserver when not in use. Sometimes we need to receive the data sent by LiveData when the page is in the Pause state, then observeForever comes in handy.

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

Multiple LiveData sources can be added through addSource. As long as one of them emits data, MediatorLiveData will trigger and forward the data. When we need to observe multiple sources, we can consider whether we can use MediatorLiveData to gather it into one emission source.

  • MediatorLiveData.removeSource

Input sources that have been added can be deleted at any time

   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

When the LiveData processed by distinctUntilChanged encounters the same value that is transmitted multiple times in a row, it will automatically intercept the value of the shield and the repeated value of the previous transmission, and deduplicate the anti-shake weapon.

   MutableLiveData source = new MutableLiveData<Integer>()
   MutableLiveData outputSource = Transformations.distinctUntilChanged(source)
复制代码
  • Transformations.map

According to the specified Function, the emission value type of the original LiveData can be converted into another type of 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

The logic of this function is very convoluted. I haven't found a way to explain it in one sentence. For the time being, I will paste the function source code and the official example of calling this function here, so that everyone can understand and understand together.

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);
    }
}
复制代码

Guess you like

Origin juejin.im/post/7097152522069999647