是什么
是一个可观察的数据存储类,且具备宿主生命周期的感知能力。
优势
- 页面不可见时不会派发消息
- 页面可见时,会立刻派发最新的一条消息给所有观察者--保证页面最新状态
- 不再需要手动处理生命周期,避免NPE
- 支持黏性事件的分发
- 共享资源,可以使用单例模式拓展 LiveData,实现全局的,不用反注册,不会内存泄漏的消息分发总线。
各类之间的关系
注册观察者流程,事件分发原理
// LiveData.class
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
// 判断是否主线程
assertMainThread("observe");
// 如果宿主已经destroy,则return
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
// 用LifecycleBoundObserver包装observer,其中包含LifecycleOwner,且能响应生命周期事, 如果页面destroy了,可以将observer自动从lifecycle移除
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 将observer和wrapper保存起来,如果之前已经存在则返回之前的wrapper,否则返回null
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// 如果之前已经添加过该observer,且observer不是绑定当前owner,抛出异常
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
// 如果之前已经添加过该observer,则不再添加,return
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
// 更新mActiveCount,判断是否触发LiveData的onActive()和onInactive()
@MainThread
void changeActiveCounter(int change) {
int previousActiveCount = mActiveCount;
mActiveCount += change;
if (mChangingActiveState) {
return;
}
mChangingActiveState = true;
try {
// 更新mActiveCount
while (previousActiveCount != mActiveCount) {
boolean needToCallActive = previousActiveCount == 0 && mActiveCount > 0;
boolean needToCallInactive = previousActiveCount > 0 && mActiveCount == 0;
previousActiveCount = mActiveCount;
// 触发onActive()或onInactive()
// 可以充分利用 onActive() 方法被激活的时机,来实现一些数据懒加载的功能。
if (needToCallActive) {
onActive();
} else if (needToCallInactive) {
onInactive();
}
}
} finally {
mChangingActiveState = false;
}
}
// 给Observer分发数据
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// 如果正在分发数据,则将mDispatchInvalidated置为true,后面分发结束后会再分发一次
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
// 如果initiator则只给initiator分发,否则给所有observer分发数据
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
// 如果正在分发数据,dispatchingValue(observer)又被调用了,则停止本次分发,重新开始分发
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
// 真正分发数据的地方
private void considerNotify(ObserverWrapper observer) {
// 如果observer所在页面不是活跃状态,则不分发数据
if (!observer.mActive) {
return;
}
// 获取observer所在页面的最新状态,有可能页面状态变了,但是还没更新Observer的mActive
// 我们仍然先判断observer.mActive,如果页面已经变为活跃状态,但是observer.mActive还没更新,即还是不活跃状态,则更新observer.mActive,但仍不分发数据
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// observer的数据版本大于LiveData的版本,即接收数据的次数大于发送数据的次数,说明observer已经收到最新的数据,不再回调observer#onChanged()通知更新
// observer的mLastVersion=-1,如果之前已经发送过数据了,即mLastVersion<mVersion,则会出现黏性事件,后注册的观察者收到了前面发送的消息
if (observer.mLastVersion >= mVersion) {
return;
}
// 每分发一次消息,则把观察者和LiveData的version对齐,防止重复发送
observer.mLastVersion = mVersion;
// 通知更新
observer.mObserver.onChanged((T) mData);
}
#########################################################
// LifecycleBoundObserver.class
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
// 当前界面是否活跃,即当前界面状态是否大于STARED
@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();
// 如果当前界面已经销毁,则移除observer
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
// 给父类OvserverWrapper设置活跃状态,如果是活跃的话分发数据
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
// ObserverWrapper.class
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
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;
}
mActive = newActive;
// 更新mActiveCount,判断是否出发LiveData的onActive()和onInactive()
changeActiveCounter(mActive ? 1 : -1);
// 如果是活跃的话,分发数据
if (mActive) {
dispatchingValue(this);
}
}
}
小结
- 首先调用LiveData#observe(owner, observer)进行注册,这时会将observer包装成LifecycleBoundObserver
- LifecycleBoundObserver继承自ObserverWrapper,保存了Observer和LifecycleOwner,所以可以回调observer#onChanged(data),也可以从LifecycleOwner中获得页面活跃状态;同时它实现了LifecycleEventObserver,所以能够监听lifecycle的生命周期事件,在页面销毁时移除observer,在页面变为活跃状态时,接收最新的数据(如果之前没有接收过的话)。
- 如果是在页面onResume是注册的观察者,onStateChanged(owner, event)会回调3次:onCreate、onStart、onResume。但是observer#onChanged(data)只会回调一次,因为onStateChanged(owner, event)会判断如果页面状态和之前一样(mActive没有改变),则return。
- 另外即使mActive改变了,但是如果数据没有改变,也不会回调observer#onChanged(data),因为LiveData会根据ObserverWrapper#mLastVersion和自身的mVersion判断数据的接收次数和发送次数是否一致:mLastVersion<mVersion则发送;否则不发送。
- LifecycleBoundObserver#onStateChanged(owner, event)回调时,会根据是否有活跃的观察者(mActiveCount)来触发LiveData#onActive()/onInactive()
- 之后就会判断页面是否活跃,如果活跃则分发数据,调用considerNotify方法,通过ObserverWrapper#mLastVersion和LiveData#mVersion来判断是否触发Observer#onChanged(data)
发送数据
// LiveData.class
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
// 加锁,防止主线程更新数据时,mPendingData被改变
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
protected void postValue(T value) {
boolean postTask;
// 加锁,防止主线程更新数据时,mPendingData被改变
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
// 如果postTask=false,说明正在等待runnable获取mPendingData更新界面,不再发送runnable
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
// 增加发送次数
mVersion++;
mData = value;
// 通知所有的observer更新数据
dispatchingValue(null);
}
数据倒灌是什么
页面在再次打开时,收到了旧数据。
比如,有3个fragment:列表、详情、编辑,它们都共享viewmodel中的同一个liveData,在编辑页编辑完后通过livedata保存数据,退出返回详情页时,详情页恢复活跃状态,会从liveData收到最新的数据更新界面。再次回退到列表页,点击另一个item打开详情页,这时详情页调用liveData#addObserver()会从liveData收到之前到旧数据,这就是数据倒灌。
如果解决黏性事件
反射干涉Version
不推荐这种方式,网上的方案是在LiveData#observe()
方法中利用反射修改LifecycleBoundObserver中的mLastVersion的值=LiveData的mVersion,但是这种方案只适合在页面的onCreate(页面还不是活跃状态)时注册observer,因为这时页面的state是INITIALIZED, 在LiveData#observe()->LifecycleRegistrty#addObserver()
中由于LifecycleRegistrty.mState=LifecycleBoundObserver.mState
,导致不会回调ObserverWithState#dispatchEvent()->LifecycleBoundObserver#onStateChanged()
,从而不会触发observer.onChanged(),也就达到了取消粘性事件的目的。但是如果在onStart()或之后(页面变为活跃状态)注册observer,由于这时页面的state是大于INITIALIZED的, 所以在LiveData#observe()->LifecycleRegistrty#addObserver()
中会触发ObserverWithState#dispatchEvent()->LifecycleBoundObserver#onStateChanged()
,也就导致observer.onChanged()被触发,还是发生粘性事件。自定义LiveData和Observer,分别在内部维护一个version。当不需要粘性事件时,在用LiveData注册Observer时,将LiveData的version赋值给observer的version;当需要粘性事件时,在用LiveData注册Observer时,设置Observer的version为-1。
参考:https://github.com/KunMinX/UnPeek-LiveData/blob/de958b679b/unpeeklivedata/src/main/java/com/kunminx/architecture/ui/callback/ProtectedUnPeekLiveData.java#L40-L176
public class ProtectedUnPeekLiveData<T> extends LiveData<T> {
private final static int START_VERSION = -1;
private final AtomicInteger mCurrentVersion = new AtomicInteger(START_VERSION);
protected boolean isAllowNullValue;
/**
* TODO tip:当 liveData 用作 event 用途时,可使用该方法来观察 "生命周期敏感" 的非粘性消息
* <p>
* state 是可变且私用的,event 是只读且公用的,
* state 的倒灌是应景的,event 倒灌是不符预期的,
* <p>
* 如果这样说还不理解,详见《LiveData 唯一可信源 读写分离设计》的解析:
* https://xiaozhuanlan.com/topic/2049857631
*
* @param owner activity 传入 this,fragment 建议传入 getViewLifecycleOwner
* @param observer observer
*/
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
super.observe(owner, createObserverWrapper(observer, mCurrentVersion.get()));
}
/**
* TODO tip:当 liveData 用作 event 用途时,可使用该方法来观察 "生命周期不敏感" 的非粘性消息
*
* @param observer observer
*/
@Override
public void observeForever(@NonNull Observer<? super T> observer) {
super.observeForever(createObserverWrapper(observer, mCurrentVersion.get()));
}
/**
* TODO tip:当 liveData 用作 state 用途时,可使用该方法来观察 "生命周期敏感" 的粘性消息
*
* @param owner activity 传入 this,fragment 建议传入 getViewLifecycleOwner
* @param observer observer
*/
public void observeSticky(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
super.observe(owner, createObserverWrapper(observer, START_VERSION));
}
/**
* TODO tip:当 liveData 用作 state 用途时,可使用该方法来观察 "生命周期不敏感" 的粘性消息
*
* @param observer observer
*/
public void observeStickyForever(@NonNull Observer<? super T> observer) {
super.observeForever(createObserverWrapper(observer, START_VERSION));
}
/**
* TODO tip:只需重写 setValue
* postValue 最终还是会经过这里
*
* @param value value
*/
@Override
protected void setValue(T value) {
mCurrentVersion.getAndIncrement();
super.setValue(value);
}
/**
* TODO tip:
* 1.添加一个包装类,自己维护一个版本号判断,用于无需 map 的帮助也能逐一判断消费情况
* 2.重写 equals 方法和 hashCode,在用于手动 removeObserver 时,忽略版本号的变化引起的变化
*/
class ObserverWrapper implements Observer<T> {
private final Observer<? super T> mObserver;
private int mVersion = START_VERSION;
public ObserverWrapper(@NonNull Observer<? super T> observer, int version) {
this.mObserver = observer;
this.mVersion = version;
}
@Override
public void onChanged(T t) {
if (mCurrentVersion.get() > mVersion && (t != null || isAllowNullValue)) {
mObserver.onChanged(t);
}
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ObserverWrapper that = (ObserverWrapper) o;
return Objects.equals(mObserver, that.mObserver);
}
@Override
public int hashCode() {
return Objects.hash(mObserver);
}
}
/**
* TODO tip:
* 通过 ObserveForever 的 Observe,需要记得 remove,不然存在 LiveData 内存泄漏的隐患,
* 保险的做法是,在页面的 onDestroy 环节安排 removeObserver 代码,
* 具体可参见 app module 中 ObserveForeverFragment 的案例
*
* @param observer observeForever 注册的 observer,或 observe 注册的 observerWrapper
*/
@Override
public void removeObserver(@NonNull Observer<? super T> observer) {
if (observer.getClass().isAssignableFrom(ObserverWrapper.class)) {
super.removeObserver(observer);
} else {
super.removeObserver(createObserverWrapper(observer, START_VERSION));
}
}
private ObserverWrapper createObserverWrapper(@NonNull Observer<? super T> observer, int version) {
return new ObserverWrapper(observer, version);
}
/**
* TODO tip:
* 手动将消息从内存中清空,
* 以免无用消息随着 SharedViewModel 的长时间驻留而导致内存溢出的发生。
*/
public void clear() {
super.setValue(null);
}
}