更新一下,添加了 LiveData 粘性消息的原因分析和解决方案
1.LiveData
LiveData
是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。生命周期处于 STARTED
或 RESUMED
状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。
2.原理
借助Lifecycle组件实现,observe
方法需要传递一个Observer
观察者
2.1 observe方法
对Observer
进行封装,并将其添加为生命周期Lifecycle
的观察者
public void observe(LifecycleOwner owner, Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
// 对Observer进一步封装,LifecycleBoundObserver间接实现LifecycleObserver接口,实现对
// 生命周期的响应
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
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;
}
owner.getLifecycle().addObserver(wrapper);
}
复制代码
2.2 LifecycleBoundObserver#onStateChanged
添加的Observe
实际实现,重写了Lifecycle
的onStateChanged
方法来实现在活跃状态时分发数据
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
// 当前状态为DESTROYED时移除观察者
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
void activeStateChanged(boolean newActive) {
// 状态没有发生改变
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
// 变成活跃状态时分发数据
if (mActive) {
dispatchingValue(this);
}
}
复制代码
2.3 数据分发给观察者
数据分发有两个时机:
- 主动调用LiveData的setValue或者postValue(也是调用setValue)方法时
- 当持有LiveData的生命组件的生命周期状态发生该变的时候,在Observer的onStateChanged方法中调用
// 第一种情况下参数为null, 第二种情况参数为当前Observer
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
// 第二种情况,当前Observer的数据分发
considerNotify(initiator);
initiator = null;
} else {
// 第一种情况,遍历对所有Observer进行数据分发
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// 观察者数据版本领先了,不用更新
// mVersion在setValue修改,表示LiveData的最新版本
// mLastVersion是Observer当前获取的数据的最新版本
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 调用我们在observe方法中传递的代码
observer.mObserver.onChanged((T) mData);
}
复制代码
3.LiveData粘性消息
3.1 粘性消息产生原因
当我们在 Fragment 页面中通过 activityViewModels 获取 ViewModel 进行数据共享的场景下,例如:在一个页面发送一个网络请求,当网络请求失败通过 ViewModel 向 LiveData 中设置一个 errorMsg,当我们关闭该页面后又重新进入该页面时,在没有进行任何操作的情况下,就会先收到请求失败的消息。这就是 LiveData 的粘性消息导致的。
由于我们通过 activityViewModels 获取的 ViewModel 的声明周期比 Fragment 的生命周期更长,在第一次关闭 Fragment 时,ViewModel 没有随着 Fragment 销毁,自然其中的 LiveData 也还存在。当我们在一次进入该 Fragment 的时候通过 vm.observe()
为 LiveData 注册观察者,LifecycleBoundObserver
是实际的类型。
下面详细分析一下 LiveData Observer 添加的代码。
// 1、为 LiveData 绑定 Observer
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
// 1.1、创建 LifecycleBoundObserver
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 1.2、保存创建的 observer
// mObservers 是一个 Map
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;
}
// 1.3、 将 创建的 LifecycleBoundObserver 注册为 Lifcycle 的观察者
owner.getLifecycle().addObserver(wrapper);
}
// 2、对用户传递的 observer 进行包装,内部持有用户传递的 observer
private abstract class ObserverWrapper {
final Observer<? super T> mObserver; // 用户传递的 obserber
boolean mActive;
int mLastVersion = START_VERSION; // observer 当前的数据版本,默认值为 -1
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
// 如果变成活跃状态则分发数据
if (mActive) {
dispatchingValue(this);
}
}
}
// 3、继承 ObserverWrapper,持有用户传递的 Observer,同时实现 LifecycleEventObserver 来感知生命周期
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() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
// 感知生命周期
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
// 生命周期变成活跃或者不活跃的情况
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
// 父类的方法
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
复制代码
可以看到在为 LiveData 添加 Observer 时,内部会创建出 LifecycleBoundObserver,该类继承 ObserverWrapper 类,同时实现了LifecycleEventObserver 接口,ObserverWrapper 内部持有我们传递的 Observer,而 LifecycleEventObserver 时 Lifecycle 中的观察者,其 onStateChanged 方法会在生命周期发生变化时回调,因此我们注册的 Observer 就可以感知生命周期,并且只在生命周期处于活跃状态的情况下才触发 LiveData 的数据分法。
上文2.3 节有提到 LiveData 数据分发的时机,一种时我们通过 setValue 改变 LiveData 时触发的对所有 Obserber 进行分发,另一种就是在 Observer 内部触发的,即在 LifecycleBoundObserver 感知到生命周期发生变化时触发了 onStateChanged
方法,其中调用 activeStateChanged
方法,在检测到生命周期处于活跃状态时分发数据。

此时我们就能够知道 LiveData 粘性数据产生的原因:Fragment 第二次进入页面时,注册的 Observer 检测到生命周期变成活跃状态,于是就想起分发了之前的数据,因此第二次进入 Fragment 的时候,我们什么也没操作就收到了数据。(这里还涉及到 Lifecycle 的一点内容,即 Lifecycle 会对后注册的观察者分发之前的生命周期事件,因此即使我们注册 LiveData的观察者时生命周期组件处于以活跃状态,但是观察者(LifecycleBoundObserver)仍然可以收到变成活跃状态的回调)。
3.2 粘性消息的处理
上文介绍了 LiveData 粘性消息产生的原因,下面介绍一下解决方案。
// 包装 LiveData 内部的变量,记录是否已经处理过了
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
fun peekContent(): T = content
}
// 对 Observer 也进行一层包装,接收到分发的数据时先判断是否之前处理过
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
override fun onChanged(event: Event<T>?) {
event?.getContentIfNotHandled()?.let {
onEventUnhandledContent(it)
}
}
}
//----------------------------使用时 --------------------------------
val l = EventObserver<Event<String>>()
l.observe(this, Observer {
})
复制代码