1. 简介
长久以来我们都要去了解Activity或者Fragment的生命周期,因为界面的生命周期是我们处理数据的基础,我们需要知道在哪个地方“才能”去做哪些事,但是这些生命周期又是极其繁琐且样板的,一般来说我们只会去处理几个经常出问题的界面,而选择性的“忽视”一些问题。对于整个App来说,生命周期是一个让人有些不安的概念,因为它总会在不经意间给我们弹出几个bug,无论是稳定性还是数据的完整性,这些不应该是我们在开发业务时关心的事情,我们专注的应该是业务本身而不是被生命周期拖累出的bug,生命周期也应该有一套属于自己的封装。
2. 使用
3. 优点
- UI和数据保持一致,在数据变更之后自动更新UI。
- 数据跟随界面(Activity/Fragment)生命周期,数据在可用时更新,在不可用时销毁,弱化生命周期的概念,同时避免组件在不可用时遭到更改而出现崩溃。
- 共享数据,可以在多个Fragmnt中共享数据。
4. 原理
4.1. 前置条件
-
理解观察者模式
观察者模式 -
理解LifeCycleEventObserver
MyLifeCycleEventObserver
理解了上述的两个条件,就能猜想到一大半的实现流程。
我们只要明确两个问题:LiveData是在什么时候去绑定生命周期的?观察者的notify又是什么时候触发的?
4.2. 如何绑定Activity的生命周期
我们在调用LiveData的时候调用的是 LiveDta.observe(LifecycleOwner owner,Observer observer),这个方法里的owner 其实就是AppCompatActivity本身。
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 存储Observer,便于后面更改值之后分发事件
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
不能重复添加
}
// 使用wrapper,接收界面生命周期的回调,类似于上文(前置条件)中的MyLifeCycleEventObserver
owner.getLifecycle().addObserver(wrapper);
}
在我们直接使用LiveData时,它已经不经意间绑定了生命周期,有了生命周期其实我们只要找准时机去触发事件就好了。
4.3. 如何更新(分发)数据
思考:我们想要触发界面的更新,即触发Activity中Observer的onChanged方法,需要在哪里调用?
既然上面说到了LifecycleEventObserver,那么我们很自然的去它的实现类去看一下
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@Override
boolean shouldBeActive() {
// 当前生命周期是否在Start之后,包括Start
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
// 反注册
removeObserver(mObserver);
return;
}
// 这里分两层,shouldBeActive其实就是判断当前生命周期是否在Start之后,其次才是active
activeStateChanged(shouldBeActive());
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
mActive = newActive;
if (mActive) {
// 可以理解为观察者的notify方法
dispatchingValue(this);
}
}
}
我们保留最简洁的代码,可以直观的看出:
- Observer在生命周期到Destroy时反注册自己
- 在每次Start之后,都会触发更新方法,不过使用了标记位来避免重复的执行
以上就是生命周期绑定的方法,下面我们分析主动的触发
@MainThread
protected void setValue(T value) {
mVersion++;
mData = value;
dispatchingValue(null);
}
setValue的方法更加简单,设置value并且触发分发,和activeStateChanged方法的处理类似,最终调用的更新方法是相同的dispatchingValue(),只是设置的变量不一样(一个是this,一个是null),这也影响了之后的处理逻辑。
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// 防止重复处理
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
// 这就是不一样的地方
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());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
在Google的代码里也少不了这样的Flag方法,虽然代码有点啰嗦,但这是一个简单易行的方案。
initiator(发起人、创始者的意思,AndroidX中变量的名字起的是真好)就是Livedata本身,如果有值直接触发这个Livedata的更新,如果没有则触发所有Observer(但不一定都会调用onChanged方法)。
在dispatchingValue方法中最后会调用considerNotify
// 这个confider也起的好,这些notify不是一定会触发,而是要经过慎重思考的。
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// 这个version也是用来减少重复处理的,每次setValue时都会version++
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 最后调用Observer的onChanged方法
observer.mObserver.onChanged((T) mData);
}
5. 总结
LiveData的实现其实不能说是复杂,但是它实现的却很巧妙,简单的使用观察者就能把一直困扰我们的生命周期的问题解决。其实这是一个很好的切入点,我们总是习惯了去做很多事,也许这些事情并不一定需要我们每次都去做,findViewById不是必须的,生命周期的控制不是必须的,数据的设置也不一定是必须的……也许我们应该跳出Android开发的思维,用更省力的角度去解决一些我们已经习以为常的不是问题的问题,也许我们能打开编程的另一扇门。
网友评论