LiveData介绍
liveData是一个可被观察的数据持有者类
,它主要是用于搭建MVVM框架,在其中充当数据持有者的角色。
特点
分开来看:
- liveDava是一个数据持有者类
- liveData可被观察,当持有的数据发生变化时,观察者(Observer)可以感知
- 在liveData中观察者(Observer)会被封装,然后观察者就可以感知到生命周期,因此就能实现仅当生命周期活跃时才会把新的数据分发给观察者
- 不需要手动取消订阅
使用
//step1
val liveData = MutableLiveData<Int>()
//step2
liveData.observe(this){
//get the value do something
}
//step3
liveData.value = 1
以上就是一个liveData的使用,在本例中step2和step3换个顺序也是一样的,因为liveData的粘性事件后面会看到。
源码分析
liveData使用太简单了这里直接看源码吧
observe
//结合上面的例子来看
//step1
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
//确保是在主线程中添加
assertMainThread("observe");
//step2
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
//step3
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//step4
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
//step5
owner.getLifecycle().addObserver(wrapper);
}
step1:添加观察者,注意参数里面还获取到了LifecycleOwner通过它就能拿到LifecycleRegistry
step5:观察者经过封装后通过addObserver就有了感知生命周期的能力了,具体用法请往下看 至于具体怎样感知生命周期的,这就涉及到lifecycle相关的知识了liveData和lifecycle关联挺深的,还没了解lifecycle的可以看下这篇文章Lifecycle使用及源码分析,总之要了解liveData的全貌请先了解lifecycle
step2:在liveData的特点第三点就说过,只有当组件的生命周期处于活跃状态时才会把数据分发给观察者,如果当前的组件都已经是DESTROYED状态了也就没必要继续添加了
step4:把ObserverWrapper(即封装好的Observer)保存到一个链表中,后续两个if会保证Observer不会被重复添加,如果重复添加的同时还和其它LifecycleOwner相关联的话会抛出异常
step3:这里的LifecycleBoundObserver是很核心的一个类,先看代码:
//首先它实现了LifecycleEventObserver接口,再配合上文step5,所以LifecycleBoundObserver的onStateChanged方法就能够获取到最新的生命周期
//而一个LifecycleBoundObserver对应了一个Observer,因此这就是Observer能够感知生命周期的由来
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
//只有LifecycleOwner的生命周期大于等于 STARTED,才称LifecycleBoundObserver是活跃的观察者
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
//当 lifecycleOwner 生命周期有变化的时候,lifecycle都会回调观察者的onStateChanged方法
//因此这里可以获取到 lifecycleOwner 最新的生命周期状态
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
//当生命周期状态来到DESTROYED的时候就会remove当前的观察者,所以我们不需要手动取消订阅
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
//调用父类 ObserverWrapper 的activeStateChanged
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
再来看下ObserverWrapper:
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
//判断观察者是否是活跃的
boolean mActive;
//当前观察者最新值版本号,初始值为 -1,与之对应的是liveData的mVersion每次调用liveData的setValue方法mVersion都会加1
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
//拿到观察者的引用
mObserver = observer;
}
//当数据观察者绑定的组件生命周期变化时,尝试将最新值分发给当前观察者
void activeStateChanged(boolean newActive) {
//如果生命周期状态没变化就直接return
if (newActive == mActive) {
return;
}
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
//如果活跃则会把最新的数据分发给当前的观察者
if (mActive) {
dispatchingValue(this);
}
}
}
到此observer相关的源码就分析完了,回顾以下
- 把observer封装到 LifecycleBoundObserver 中
- 通过lifecycleOwner把LifecycleBoundObserver加入进去,使observer有感知生命周期的能力
- 接下来就靠生命周期的驱动了,由于lifecycle中也是粘性事件,所以此时会依次分发生命周期到onStateChanged中
- 在onStateChanged中如果生命周期状态是DESTROYED则删除此observer,否则调用父类的activeStateChanged
- 如果生命周期状态有变化,如果最新的是active则会把最新的数据分发给当前的observer
根据上面的分析 LiveData 有两次机会通知观察者,与之对应的有两种分发值的方式:
- 当值更新时,遍历所有观察者将最新值分发给它们。
- 当与观察者绑定组件的生命周期发生变化时,将最新的值分发给指定观察者。上面分析的就是第二种情况
现在来看看第一种分发setValue
setValue
postValue适用于子线程,在里面会实现线程的切换,最终也会走setValue
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
代码很简单首先是必须在主线程-->mVersion会加1-->更新mData为最新的值-->分发;注意这里的分发和上文activeStateChanged中的分发不一样这里传的是null,来看下dispatchingValue到底做了什么
分发数据
@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
//通过considerNotify方法去分发到指定的observer中
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
//通过considerNotify方法去分发到指定的observer中
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
首先很清晰的可以看到传null是分发给所有的observer,这个时候还没有区分是否活跃,如果initiator不为空就只分发给它。 这里得仔细体会mDispatchingValue、mDispatchInvalidated这两个变量:
mDispatchingValue 这个变量用来控制,是否进入while循环以及while循环是否已经结束
,只有当mDispatchingValue为false才能开启这个while循环,在开启前会把mDispatchingValue置为true,知道while循环结束才会再置为false即一次只能开启一个while循环。
mDispatchInvalidated 这个变量用来控制for循环是否要重新开始
,当第二次调用dispatchingValue方法假如上一次while循环未结束,mDispatchInvalidated会置为true这只会中断for循环,此时while循环不会结束,然后mDispatchInvalidated再次被置为false,重头执行for循环,假如没有新的分发过来for循环完成后while循环也就结束了。这主要是考虑到旧数据还没分发完新的数据又来了,为了节约资源当然是马上停止分发重新开始分发最新的数据。
之前说了dispatchValue还没有区分observer是否活跃而是都调用considerNotify,看下considerNotify又做了什么:
@SuppressWarnings("unchecked")
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
//当前observer如果是非活跃的,即对应的lifecycleOwner生命周期状态小于STARTED
//那么会调用observer的activeStateChanged方法去改变mActive的值,这要是考虑当生命周期状态又恢复活跃的时候还需要把最新的值再单独分发给此observer
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//mLastVersion大于等于mVersion的话说明值已经是最新的了
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//真正回调的地方
observer.mObserver.onChanged((T) mData);
}
到此整个liveData的数据回调的流程就全部结束,和lifecycle的联系是很紧密的,所以不要忽略掉observer感知生命周期这一特点,不要忽略LifecycleBoundObserver的onStateChanged方法
,就是因为生命周期的驱动新添加的observer才能拿到老的值。
一些问题
什么情况下 LiveData 会丢失数据?
在高频数据更新的场景下使用 LiveData.postValue() 时,会造成数据丢失。因为“设值”和“分发值”是分开执行的,之间存在延迟。值先被缓存在变量中,再向主线程抛一个分发值的任务。若在这延迟之间再一次调用 postValue(),则变量中缓存的值被更新,之前的值在没有被分发之前就被擦除了。
在 Fragment 中使用 LiveData
因为 Fragment 和其中的 View 生命周期不完全一致。LiveData 内部判定生命周期为 DESTROYED 时,才会移除数据观察者。存在一种情况,当 Fragment 之间切换时,被替换的 Fragment 不执行 onDestroy(),但是view会被重建,所以在fragment中我们需要考虑liveData.observe的时机,否则当之前的fragment再次展示时会再次订阅而多出一个Observer。