Android LiveData 浅析

什么是LiveData

官网中是这么定义的:LiveData 是一种可观察的数据存储器类.具有生命周期感知能力

如何理解 LiveData 具有生命周期感知能力

当界面处于可见(激活状态)时候才能收到数据的变化

举个简单的例子,两个界面,MainAct 和 SecondAct 共同处理一个 LiveData

界面如下

MainActSecondAct

通过打印能够看到

1
2
3
4
5
6
7
8
9
10
11
2020-09-17 20:12:35.877 I: main Act data 1
2020-09-17 20:12:36.828 I: main Act data 2
2020-09-17 20:12:37.505 I: main Act data 3
2020-09-17 20:12:38.920 I: Main Act 跳转 Second Act
2020-09-17 20:12:38.993 I: second Act data 3
2020-09-17 20:12:44.384 I: second Act data 4
2020-09-17 20:12:44.977 I: second Act data 5
2020-09-17 20:12:45.360 I: second Act data 6
2020-09-17 20:12:45.570 I: second Act data 7
2020-09-17 20:12:47.864 I: second Act finish
2020-09-17 20:12:47.948 I: main Act data 7
  • 当我们点击到3的时候 跳转到 SecondAct 界面 立马触发了 livedata 将 在SecondAct 的状态改成3
  • 在SecondAct 的时候 点击+1 只有SecondAct 界面发生变化,MainAct 不会发生变化
  • 当回退到MainAct 的时候 立马触发了MainAct 的 livedata 变化 并且只会显示最新的状态

liveData 是如何工作的

基于上面的小示例,我们能够大概猜测到,MainAct 和 SecondAct 两个界面都注册了观察者,被livedata 保存了起来,当点击+1 的时候,在遍历所有的观察者,通知其状态发生了变化,

首先 livedata 有一个观察者,观察状态变化的,内部呢,也有一个观察者,通过lifecycle 观察界面的生命周期变化

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
//LiveData

private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
//判断是否是主线程
assertMainThread("observe");
// 如果当前的 lifecycle 已经GG了 就不管了
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//创建一个 lifecycle 的观察者
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, 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;
}
// 这边是lifecycle 的观察者
owner.getLifecycle().addObserver(wrapper);
}

LiveData 会将所有的观察者添加到Map 中保存

当我们+1 的时候

1
2
3
4
5
6
7
8
9
10
//LiveData
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
//Version 累加
mVersion++;
//记录当前最新的 data
mData = value;
dispatchingValue(null);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//LiveData
void dispatchingValue(@Nullable ObserverWrapper initiator) {
//省略代码
do {
//省略代码
if (initiator != null) {
considerNotify(initiator);
} else {
//遍历所有的状态观察者
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
//通知改变
considerNotify(iterator.next().getValue());
}
}
} while (mDispatchInvalidated);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//LiveData
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}

if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//默认是 -1 上面在我们setValue 的时候 Version +1 所以当前的 Version ==0
// -1 >= 0 不满足
if (observer.mLastVersion >= mVersion) {
return;
}
//记录当前的 version == 0
observer.mLastVersion = mVersion;
// 传递 数据变化
observer.mObserver.onChanged((T) mData);
}

就这样我们完成了一次状态的变化

当setValue 时候,会遍历所有的状态观察者 并通知数据变化

livedata 如何处理未激活的观察者不接受变化的数据

还是上面的小例子, 在SecondAct 的时候 点击+1 只有SecondAct 界面发生变化,MainAct 不会发生变化

在上面分析LiveData 如何通知发送数据变化的时候,有下面的方法,这方法有一个细节,判断了是否是在激活状态,如果不是激活状态就不执行change

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//LiveData
private void considerNotify(ObserverWrapper observer) {
//在这里判断当前的观察者是否属于激活状态
if (!observer.mActive) {
return;
}

if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;

observer.mObserver.onChanged((T) mData);
}

跟着这个状态寻找,可以看到 livedata 是 通过 LifeCycle 接受观察者的状态的

1
2
3
4
5
6
7
8
9
10
11
12
13
//LifecycleBoundObserver
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
//这里是 监听界面变化的 观察者
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//当界面生命周期发生变化的时候 调用下面的方法
activeStateChanged(shouldBeActive());
}
}

而这个LifeCycle在添加观察者的时候就已经被LifeCycle 添加到自己的观察者中

在我们调用 observe方法的时候 创建了 LifecycleBoundObserver

1
2
3
4
5
6
7
8
//LiveData
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
//创建了一个 LifecycleBoundObserver
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//通过LifeCycle 添加
owner.getLifecycle().addObserver(wrapper);
}

详细看一下这方法,判断如果状态不相同,就修改状态,而这个仅仅是对于 调用了 observe 方法的 observer 才生效,每一个 observer 维护这自己的 状态

这里当刚刚被激活的时候,newActive == true, 当前的 mActiveCount == 0, 然后执行 +1 的操作 得到 mActiveCount == 1,下面的逻辑判断 因为 wasInactive 和 mActive 都是 true, 通知被激活了,执行 onActive

再往下 发现 mActiveCount ==1 所以不执行 onInactive 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//LiveData / ObserverWrapper
void activeStateChanged(boolean newActive) {
//当状态相同的时候 不会触发
if (newActive == mActive) {
return;
}
//修改 observer 当前LiveData 的状态
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
//通知 observer livedata 数据被激活
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
//通知observer LiveData 数据处于不活跃状态
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}

补充一下,因为这里会执行多次,所以放上一个 手写的时序图

能够知道,其实正在改变状态的是在 onStart 和 onStop

到这里 我们知道了 为什么 在SecondAct 的时候 点击+1 只有SecondAct 界面发生变化,MainAct 不会发生变化 的原因。

LiveData 通过观察者内部自己维护的状态进行判断,是否处于激活状态,而这些状态则是通过LifeCycle 进行触发

当界面激活的时候,livedata 如何将最新的数据发给观察者

在上面的 解释 我们知道,如果MainAct 重新 onStart 那么 observer 所维护的 激活状态就被打开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//LiveData / ObserverWrapper
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
//当激活状态被激活的时候,会执行一次 分发的逻辑
if (mActive) {
dispatchingValue(this);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//LiveData
void dispatchingValue(@Nullable ObserverWrapper initiator) {
//省略代码
do {
//省略代码
if (initiator != null) {
considerNotify(initiator);
} else {
//遍历所有的状态观察者
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
//通知改变
considerNotify(iterator.next().getValue());
}
}
} while (mDispatchInvalidated);
}

在这里的时候,想象一下,MainAct 因为没被激活,所以 他所维护的 observer 记录的 version 还是 之前 的 version 而 真正的version 因为在 SecondAct 一直被++ 所以远大于 Main 记录的值。
当MainAct onStart 以后,会立马重新判断,这个时候 状态已经改成被激活了,并且 observer 记录的version < 真正的Version 所以会执行一次changed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//LiveData
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
//未被激活 执行这里
return;
}

if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// mainAct记录的 < 当前记录的值
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 传递 数据变化 最终执行到这里
observer.mObserver.onChanged((T) mData);
}

LiveData 通过LifeCycle 得知自己 被激活,然后通过记录的Version 判断是否需要重新changed

LiveData 不建议当做Event 使用

还是之前的示例,当回到FirstAct 的时候,livedata 依然能够收到事件,作为事件总线,这种是不被允许的,不过有大佬做了一个 LiveDataBus 能够替换掉EventBus

onActive 和 onInactive

在上面说明了,对于LiveData 本身而言,是无意义的,是告诉开发者 您当前的Observer 所观察的 LiveData 是否被激活

observeForever

这个方法和 observe 最大的区别在源码中可以看到

observe。创建的是一个 LifecycleBoundObserver ,他的判断条件根据lifecycle 判断

1
2
3
4
5
//LifecycleBoundObserver
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

当界面onDestory 的时候

1
2
3
4
5
6
7
8
9
10
//LifecycleBoundObserver
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
//remove了
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}

observeForever 创建的是一个 AlwaysActiveObserver,则直接返回为true

1
2
3
4
5
//AlwaysActiveObserver
@Override
boolean shouldBeActive() {
return true;
}

因为不在具有生命感知能力,就需要手动去自己remove,并且 即使mainAct 界面处于未被激活的状态 也依然可以收到

那么他是如何处理即使在未被激活的界面 依然能够触发变化呢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//LiveData
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
//很粗暴,直接将界面状态变成激活状态,不高那么多花里胡哨的
wrapper.activeStateChanged(true);
}

observeForever 需要开发者手动去 remove 而observe 则是由LiveData 自行remove