MVVM 系列之二:LiveData,android 程序开发教程
此例子把 Integer 类型的 liveData1 修改为 String 类型的 liveDataMap。结果如下:
2020-12-06 17:01:56.095 21998-21998/com.hfy.androidlearning I/Lifecycle_Test: apply: 100 + Transformations.map
2020-12-06 17:01:56.095 21998-21998/com.hfy.androidlearning I/Lifecycle_Test: onChanged1: 100 + Transformations.map
2.3.2 数据切换 - Transformations.switchMap
如果想要根据某个值 切换观察不同 LiveData 数据,则可以使用 Transformations.switchMap()方法。
//两个 liveData,由 liveDataSwitch 决定 返回哪个 livaData 数据
MutableLiveData<String> liveData3 = new MutableLiveData<>();
MutableLiveData<String> liveData4 = new MutableLiveData<>();
//切换条件 LiveData,liveDataSwitch 的 value 是切换条件
MutableLiveData<Boolean> liveDataSwitch = new MutableLiveData<>();
//liveDataSwitchMap 由 switchMap()方法生成,用于添加观察者
LiveData<String> liveDataSwitchMap = Transformations.switchMap(liveDataSwitch, new Function<Boolean, LiveData<String>>() {
@Override
public LiveData<String> apply(Boolean input) {
//这里是具体切换逻辑:根据 liveDataSwitch 的 value 返回哪个 liveData
if (input) {
return liveData3;
}
return liveData4;
}
});
liveDataSwitchMap.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.i(TAG, "onChanged2: " + s);
}
});
boolean switchValue = true;
liveDataSwitch.setValue(switchValue);//设置切换条件值
liveData3.setValue("liveData3");
liveData4.setValue("liveData4");
liveData3、liveData4 是两个数据源,有一个判断条件来决定 取哪一个数据 ,这个条件就是 liveDataSwitch,如果值为 true 则取 liveData3,false 则取 liveData4。 Transformations.switchMap()就用于实现这一逻辑,返回值 liveDataSwitchMap 添加观察者就可以了。 结果如下:
2020-12-06 17:33:53.844 27347-27347/com.hfy.androidlearning I/Lifecycle_Test: switchValue=true
2020-12-06 17:33:53.847 27347-27347/com.hfy.androidlearning I/Lifecycle_Test: onChanged2: liveData3
2020-12-06 17:34:37.600 27628-27628/com.hfy.androidlearning I/Lifecycle_Test: switchValue=false
2020-12-06 17:34:37.602 27628-27628/com.hfy.androidlearning I/Lifecycle_Test: onChanged2: liveData4
(Transformations 对 LivaData 这两个用法和 Rxjava 简直一毛一样)
2.3.3 观察多个数据 - MediatorLiveData
MediatorLiveData 是 LiveData 的子类,允许合并多个 LiveData 源。只要任何原始的 LiveData 源对象发生更改,就会触发 MediatorLiveData 对象的观察者。
MediatorLiveData<String> mediatorLiveData = new MediatorLiveData<>();
MutableLiveData<String> liveData5 = new MutableLiveData<>();
MutableLiveData<String> liveData6 = new MutableLiveData<>();
//添加 源 LiveData
mediatorLiveData.addSource(liveData5, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.i(TAG, "onChanged3: " + s);
mediatorLiveData.setValue(s);
}
});
//添加 源 LiveData
mediatorLiveData.addSource(liveData6, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.i(TAG, "onChanged4: " + s);
mediatorLiveData.setValue(s);
}
});
//添加观察
mediatorLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.i(TAG, "onChanged5: "+s);
//无论 liveData5、liveData6 更新,都可以接收到
}
});
liveData5.setValue("liveData5");
//liveData6.setValue("liveData6");
例如,如果界面中有可以从本地数据库或网络更新的 LiveData 对象,则可以向 MediatorLiveData 对象添加以下源:
与存储在本地数据库中的数据关联的 liveData5
与从网络访问的数据关联的 liveData6
Activity 只需观察 MediatorLiveData 对象即可从这两个源接收更新。 结果如下:
2020-12-06 17:56:17.870 29226-29226/com.hfy.androidlearning I/Lifecycle_Test: onChanged3: liveData5
2020-12-06 17:56:17.870 29226-29226/com.hfy.androidlearning I/Lifecycle_Test: onChanged5: liveData5
(Transformations 也是对 MediatorLiveData 的使用。)
LiveData 的使用就讲完了,下面开始源码分析。
3、源码分析
======
前面提到 LiveData 几个特点,能感知生命周期状态变化、不用手动解除观察等等,这些是如何做到的呢?
3.1 添加观察者
LiveData 原理是观察者模式,下面就先从 LiveData.observe()方法看起:
/**
添加观察者. 事件在主线程分发. 如果 LiveData 已经有数据,将直接分发给 observer。
观察者只在 LifecycleOwner 活跃时接受事件,如果变为 DESTROYED 状态,observer 自动移除。
当数据在非活跃时更新,observer 不会接收到。变为活跃时 将自动接收前面最新的数据。
LifecycleOwner 非 DESTROYED 状态时,LiveData 持有 observer 和 owner 的强引用,DESTROYED 状态时自动移除引用。
@param owner 控制 observer 的 LifecycleOwner
@param observer 接收事件的 observer
*/
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// LifecycleOwner 是 DESTROYED 状态,直接忽略
return;
}
//使用 LifecycleOwner、observer 组装成 LifecycleBoundObserver,添加到 mObservers 中
Li
fecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers 中.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
//!existing.isAttachedTo(owner)说明已经添加到 mObservers 中的 observer 指定的 owner 不是传进来的 owner,就会报错“不能添加同一个 observer 却不同 LifecycleOwner”
throw new IllegalArgumentException("Cannot add the same observer"
" with different lifecycles");
}
if (existing != null) {
return;//这里说明已经添加到 mObservers 中,且 owner 就是传进来的 owner
}
owner.getLifecycle().addObserver(wrapper);
}
首先是判断 LifecycleOwner 是 DESTROYED 状态,就直接忽略,不能添加。接着使用 LifecycleOwner、observer 组装成 LifecycleBoundObserver 包装实例 wrapper,使用 putIfAbsent 方法 observer-wrapper 作为 key-value 添加到观察者列表 mObservers 中。(putIfAbsent 意思是只有列表中没有这个 observer 时才会添加。)
然后对添加的结果进行判断,如果 mObservers 中已经存在此 observer key,但 value 中的 owner 不是传进来的 owner,就会报错“不能添加同一个 observer 却是不同 LifecycleOwner”。如果是相同的 owner,就直接 returne。
最后用 LifecycleOwner 的 Lifecycle 添加 observer 的封装 wrapper。
另外,再看 observeForever 方法:
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
" with different lifecycles");
}
if (existing != null) {
return;
}
wrapper.activeStateChanged(true);
}
和 observe()类似,只不过 会认为观察者一直是活跃状态,且不会自动移除观察者。
3.2 事件回调
LiveData 添加了观察者 LifecycleBoundObserver,接着看如何进行回调的:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() { //至少是 STARTED 状态
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);//LifecycleOwner 变成 DESTROYED 状态,则移除观察者
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
LifecycleBoundObserver 是 LiveData 的内部类,是对原始 Observer 的包装,把 LifecycleOwner 和 Observer 绑定在一起。当 LifecycleOwner 处于活跃状态,就称 LifecycleBoundObserver 是活跃的观察者。
它实现自接口 LifecycleEventObserver,实现了 onStateChanged 方法。上一篇[Lifecycle](
)中提到 onStateChanged 是生命周期状态变化的回调。
在 LifecycleOwner 生命周期状态变化时 判断如果是 DESTROYED 状态,则移除观察者。LiveData 自动移除观察者特点就来源于此。 如果不是 DESTROYED 状态,将调用父类 ObserverWrapper 的 activeStateChanged()方法处理 这个生命周期状态变化,shouldBeActive()的值作为参数,至少是 STARTED 状态为 true,即活跃状态为 true。
private abstract class ObserverWrapper {
...
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;//活跃状态 未发生变化时,不会处理。
}
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;//没有活跃的观察者
LiveData.this.mActiveCount += mActive ? 1 : -1;//mActive 为 true 表示变为活跃
if (wasInactive && mActive) {
onActive();//活跃的观察者数量 由 0 变为 1
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive(); //活跃的观察者数量 由 1 变为 0
}
if (mActive) {
dispatchingValue(this);//观察者变为活跃,就进行数据分发
}
}
}
ObserverWrapper 也是 LiveData 的内部类。mActive 是 ObserverWrapper 的属性,表示此观察者是否活跃。如果活跃状态 未发生变化时,不会处理。
LiveData.this.mActiveCount == 0 是指 LiveData 的活跃观察者数量。活跃的观察者数量 由 0 变为 1、由 1 变为 0 会分别调用 LiveData 的 onActive()、onInactive()方法。这就是前面提到的扩展使用
的回调方法。
最后观察者变为活跃,就使用 LiveData 的 dispatchingValue(observerWrapper)进行数据分发:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;//如果当前正在分发,则分发无效,return
return;
}
mDispatchingValue = true; //标记正在分发
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator); //observerWrapper 不为空,使用 considerNotify()通知真正的观察者
initiator = null;
} else { //observerWrapper 为空,遍历通知所有的观察者
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
如果当前正在分发,则分发无效;observerWrapper 不为空,就使用 considerNotify()通知真正的观察者,observerWrapper 为空 则遍历通知所有的观察者。 observerWrapper 啥时候为空呢?这里先留个疑问。 继续看 considerNotify()方法:
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return; //观察者非活跃 return
}
//若当前 observer 对应 owner 非活跃,就会再调用 activeStateChanged 方法,并传入 false,其内部会再次判断
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);//回调真正的 mObserver 的 onChanged 方法
}
先进行状态检查:观察者是非活跃就 return;若当前 observer 对应的 owner 非活跃,就会再调用 activeStateChanged 方法,并传入 false,其内部会再次判断。最后回调真正的 mObserver 的 onChanged 方法,值是 LivaData 的变量 mData。
到这里回调逻辑也通了。
3.3 数据更新
LivaData 数据更新可以使用 setValue(value)、postValue(value),区别在于 postValue(value)用于 子线程:
//LivaData.java
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue); //也是走到 setValue 方法
}
};
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);//抛到主线程
}
postValue 方法把 Runable 对象 mPostValueRunnable 抛到主线程,其 run 方法中还是使用的 setValue(),继续看:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
setValue()把 value 赋值给 mData,然后调用 dispatchingValue(null),参数是 null,对应前面提到的 observerWrapper 为空的场景,即 遍历所有观察者 进行分发回调。
到这里观察者模式完整的实现逻辑就梳理清晰了:LivaData 通过 observe()添加 与 LifecycleOwner 绑定的观察者;观察者变为活跃时回调最新的数据;使用 setValue()、postValue()更新数据时会通知回调所有的观察者。
3.4 Transformations 原理
最后来看下 Transformations 的 map 原理,如何实现数据修改的。switchMap 类似的。
//Transformations.java
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;
}
new 了一个 MediatorLiveData 实例,然后将 传入的 livaData、new 的 Observer 实例作为参数 调用 addSource 方法:
//MediatorLiveData.java
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()) {
//MediatorLiveData 有活跃观察者,就 plug
e.plug();
}
}
MediatorLiveData 是 LiveData 的子类,用来观察其他的 LiveData 并在其 OnChanged 回调时 做出响应。传入的 livaData、Observer 包装成 Source 实例,添加到列表 mSources 中。
如果 MediatorLiveData 有活跃观察者,就调用 plug():
//MediatorLiveData.java
private static class Source<V> implements Observer<V> {
final LiveData<V> mLiveData;
final Observer<? super V> mObserver;
int mVersion = START_VERSION;
评论