0%

livedata架构组件原理解析

提纲

  • 什么是LivaData
  • LiveData衍生类
  • LiveData核心方法
  • LiveData事件分发实现原理

什么是LiveData

LiveData 组件是 Jetpack 新推出的基于观察者的消息订阅/分发组件,具有宿主(Activity、Fragment)生命周期感知能力,这种感知能力可确保 LiveData 仅分发消息给处于活跃状态的观察者,即只有处于活跃状态的观察者才能收到消息

活跃状态:通常情况下等于 Observer 所在宿主处于 started,resumed 状态,如果使用 observeForever 注册的,则一直处于活跃状态。

LiveData 的消息分发机制,是以往的 Handler、EventBus、RxjavaBus 无法比拟的,它们不会顾及当前页面是否可见,一股脑的有消息就转发。导致即便应用在后台页面不可见的情况下还在做一些无用的工作抢占资源。举个例子,细心的同学可以发现微信消息列表是在页面可见状态时才会更新列表最新信息的。

LiveData 的出现解决了以往使用 callback 回调可能带来的NPE,生命周期越界,后台任务抢占资源等问题。

LiveData的优势

确保界面符合数据状态LiveData 遵循观察者模式。当生命周期状态发生变化时,LiveData 会通知 [Observer]对象并把最新数据派发给它。观察者可以在收到onChanged事件时更新界面,而不是在每次数据发生更改时立即更新界面。

不再需要手动处理生命周期只需要观察相关数据,不用手动停止或恢复观察。LiveData 会自动管理Observer的反注册,因为它能感知宿主生命周期的变化,并在宿主生命周期的onDestory自动进行反注册。因此使用LiveData做消息分发不会发生内存泄漏

数据始终保持最新状态如果宿主的生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。

支持黏性事件的分发即先发送一条数据,后注册一个观察者,默认是能够收到之前发送的那条数据的

共享资源我们可以使用单例模式拓展 LiveData,实现全局的消息分发总线。

LiveData 实现原理

黏性消息分发流程,即新注册的 observer 也能接收到前面发送的最后一条数据。原因就在于LiveData 每次发送一条数据它的 mVersion 都会 +1。但是新注册的 Observer 的 lastVersion=0 ,图中的 considerNotify 方法就会把前面发送的数据分发给新注册的 Observer 了。

LiveData 注册观察者触发消息分发流程原理分析

observe 注册时,可以主动跟宿主生命周期绑定,不用反注册:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
//1. 首先来个断言,这个方法只能在主线程调用,observeForever也是。
assertMainThread("observe");
//2.其次把注册进来的observer包装成 一个具有生命周边边界的观察者
//它能监听宿主被销毁的事件,从而主动的把自己反注册,避免内存泄漏
//此时观察者是否处于活跃状态就等于宿主是否可见
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//3.接着会判断该观察是否已经注册过了,如果是则抛异常,所以要注意,不允许重复注册
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
//4.这一步才是关键
//利用Lifecycle,把观察者注册到进去,才能监听到宿主生命周期状态的变化,对不对?
//根据上节的分析,一旦一个新的观察者被添加,Lifecycle也会同步它的状态和宿主一致对不对?此时会触发观察者的onStateChanged方法
owner.getLifecycle().addObserver(wrapper);
}

LifecycleBoundObserver 监听宿主的生命周期,并且宿主不可见时不分发任何数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
}

@Override
boolean shouldBeActive() {
//使用observer方法注册的观察者都会被包装成LifecycleBoundObserver
//观察者是否活跃就等于宿主 的状态是否大于等于STARTED,
//如果页面当前不可见,你发送了一条消息,此时是不会被分发的,可以避免后台任务抢占资源,当页面恢复可见才会分发。
//注意:如果使用observerForever注册的观察者,
//会被包装成AlwaysActiveObserver,它的shouldBeActive一致返回true.即便在页面不可见也能收到数据
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//在这里如果监听到宿主被销毁了,则主动地把自己从livedata的观察者中移除掉
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//否则说明宿主的状态发生了变化,此时会判断宿主是否处于活跃状态
activeStateChanged(shouldBeActive());
}
}

ObserverWrapper 状态变更后,如果观察者处于活跃状态会触发数据的分发流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
abstract class ObserverWrapper{
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION//这里就等于-1,没有主动和LiveData的mVersion对齐,为黏性事件埋下了伏笔

void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
//更改观察者的状态
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
//如果此时有且只有一个活跃的观察者则触发onActive
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
//没有任何一个活跃的观察者则触发onInactive
//利用这个方法被触发的时机,可以做很多事,比如懒加载,资源释放等
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
//如果此时观察者处于活跃状态,下面就开始分发数据了
//请注意,这里传递了this = observer
if (mActive) {
dispatchingValue(this);
}
}
}

dispatchingValue 数据分发流程控制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
//如果传递的观察者不为空,则把数据分发给他自己。这个流程是新注册观察者的时候会被触发
considerNotify(initiator);
initiator = null;
} else {
//否则遍历集合中所有已注册的的观察者,逐个调用considerNotify,分发数据
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}

considerNotify 数据真正分发的地方,需要满足三个套件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void considerNotify(ObserverWrapper observer) {
//观察者当前状态不活跃不分发
if (!observer.mActive) {
return;
}
//观察者所在宿主是否处于活跃状态,否则不分发,并且更改观察者的状态为false
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//此处判断观察者接收消息的次数是否大于等于 发送消息的次数
//但是observer被创建之初verison=-1
//如果此时LiveData已经发送过数据了。这里就不满足了,就出现黏性事件了,后注册的观察者收到了前面发送的消息。
if (observer.mLastVersion >= mVersion) {
return;
}
//每分发一次消息,则把观察者和LiveData的version对齐,防止重复发送
observer.mLastVersion = mVersion;
//最后的数据传递
observer.mObserver.onChanged((T) mData);
}

普通消息分发流程。即调用 postValue,setValue 才会触发消息的分发:

LiveData%20%E6%9E%B6%E6%9E%84%E7%BB%84%E4%BB%B6%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90%203f9fc9a684d24a978a9ac59d71f35860/5ee8243109c6b1c211470764.png

我们经常会使用observer(),observeForever()去注册观察者,它俩有什么区别呢?

  • **observer()**:不需要手动反注册,并且宿主不可见时收不到消息,当宿主恢复可见时,会立刻收到最新的数据;
  • **observeForever()**:需要自行手动反注册,并且无论宿主是否可见,都能够收到消息;
  • 可以充分利用 onActive() 方法被激活的时机,来实现一些数据懒加载的功能。