Architecture-LiveData
2019-12-02 本文已影响0人
白六小子
LiveData 是一个可以感知 Activity 、Fragment生命周期的数据容器。 当 LiveData 所持有的数据改变时,它会通知相应的界面代码进行更新。同时,LiveData 持有界面代码 Lifecycle 的引用,这意味着它会在界面代码(LifecycleOwner)的生命周期处于 started 或 resumed 时作出相应更新,而在 LifecycleOwner 被销毁时停止更新。
所以LiveData有三个优点
- 不用手动控制生命周期
- 不用担心内存泄漏
- 天然的观察者模式,观察数据变化
- LiveData在处于inactive状态时,不会数据更新的通知,回到active状态时,会刷新最新的变化数据。
LiveData是抽象类,实际使用的是它的子类MutableLiveData
public class MutableLiveData<T> extends LiveData<T> {
// 可以在子线程设置数据
@Override
public void postValue(T value) {
super.postValue(value);
}
// 只能在主线程
@Override
public void setValue(T value) {
super.setValue(value);
}
}
- LiveData在纯数据情况下替代单例
通过这样简单的封装,LiveData可以完成跨Activity的数据共享。注意,ViewModel并不能跨Activity共享数据,VM必须依赖于单个Activity的创建和销毁。
public class SingleLiveData extends MutableLiveData<T> {
private static SingleLiveData sInstance;
private SingleLiveData() {
}
@MainThread
public static SingleLiveData getInstance() {
if (sInstance == null) {
sInstance = new SingleLiveData();
}
return sInstance;
}
@Override
public void setValue(T value) {
super.setValue(value);
}
@Override
public void postValue(T value) {
super.postValue(value);
}
}
- LiveData感知生命周期变化
在声明周期变化、移除观察者、数据变化、observeForever情况下都会调到这个方法,最终调用considerNotify通知观察者数据发生改变。
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
- Transformations
4.1 Map转换:
本质上是一种针对LiveData返回的数据的适配器作用。如LiveData返回Integer类型,而数据接收处要使用String类型,可以使用map进行如下转换
mNumberLiveData = new MutableLiveData<Integer>();
Transformations.map(mNumberLiveData, new Function<Integer, String>() {
@Override
public String apply(Integer integer) {
return "" + integer;
}
}).observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
Log.d(TAG, "onChanged: " + s);
}
});
addSource的时候Observer会观察source的变化,source数据变化回调到Observer的onChanged,随机引起map返回的LiveData即result调用setValue通知result的观察者数据发生变化
@MainThread
public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source,
@NonNull final Function<X, Y> func) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(func.apply(x));
}
});
return result;
}
4.2 switchMap转换
将初始的LiveData经过switchMap后转换成另一种形式的数据,并返回一个LiveData
比如,我们一方面需要一个存储 userId 的 LiveData,另一方面又需要维护一个存储 User 信息的 LiveData,而后者的 User 则是根据 userId 来从数据库中查找的,二者需要对应。这时候我们就可以使用Transformations类的switchMap(...)操作符。
MutableLiveData<String> userIdLiveData = new MutableLiveData<>();
LiveData<User> userLiveData = Transformations.switchMap(userIdLiveData, new Function<String, LiveData<User>>() {
@Override
public LiveData<User> apply(String userId) {
// 根据 userId 返回一个 LiveData<User>,可以通过Room来获取
return getUser(userId);
}
});
@MainThread
public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger,
@NonNull final Function<X, LiveData<Y>> func) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(trigger, new Observer<X>() {
LiveData<Y> mSource;
@Override
public void onChanged(@Nullable X x) {
LiveData<Y> newLiveData = func.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;
}