目录
源码解析目录
前言
Android应用开发的一大问题就是架构缺失,至少我观察到的是这样的。我觉得不能苛责说这是程序员水平的问题,Android本身也有它的问题。Android诞生已经超过十年了,但是Android平台并没有给我们提供一种简单明了易用的方案,来解决代码放哪这么一个基本的问题。所以,造成的结果就是不知道放哪那就往四大组件里面堆吧,堆得太多了,那就写个Util类吧,仅此而已。
Google估计也是发现了这种问题,在2017年推出了官方架构,AAC。虽然说有些晚,但是效果还是很显著的,让Android应用开发一下子从刀耕火种的原始社会,直接来到了现代化社会。不得不说,Google一出手,就知道有没有。Google I/O 2019上公布的数据说,Google Play上的Top 1000应用中有80%采用了AAC架构。足可见AAC的受欢迎程度。
问题
数据是如何传输的是任何架构的关键环节,而AAC架构的数据传输就是依靠LiveData。LiveData可谓是为Android量身定做的数据传输方案,它不仅解决了数据如何传输的问题,又解决了Android平台生命周期复杂性的问题。LiveData“神奇”的一点就在于它是可感知生命周期的,onStart之后观察者才会被通知,onDestroy的时候观察者又会被自动移除,最大程度上避免了null指针和内存泄漏。这就是我们要在LiveData源码中寻找的答案,这一切是怎么实现的。(源码版本androidx.lifecycle:lifecycle-extensions:2.2.0-alpha01)
1. LiveData的职责
LiveData应该完成哪些职责呢?无外这几点:
- 添加包含LifecycleOwner的观察者
- 在LifecycleOwner的ON_DESTROY事件时,移除观察者
- LiveData的数据变化后,是否通知观察者(观察者可能未处于STARTED或者RESUMED状态)
- 生命周期状态变化时,是否通知观察者(可能此时生命周期来到了STARTED或者RESUMED状态,之前又积压了未通知的数据)
- 通知观察者,并且避免重复通知
LiveData源码的主要内容就是处理这些问题。
2. LiveData添加观察者
为LiveData添加带LifecycleOwner的观察者的方式特别简单,调用其observe
方法即可:
public abstract class LiveData {
/**
* LiveData的观察者集合,以键值对的形式被添加进去,
* 原始观察者Observer是键,对Observer的包装类ObserverWrapper是值。
* SafeIterableMap是支持库内部实现的一种数据结构,底部以链表实现,表面上看上去却像个Map
*/
private SafeIterableMap, ObserverWrapper> mObservers =
new SafeIterableMap<>();
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
assertMainThread("observe");
//如果Lifecycle已经处于DESTROYED状态,直接返回
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//对我们提供的observer进行包装,看包装类的名字 LifecycleBoundObserver 就知道,
// 要包装成一个跟生命周期关联的观察者类
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//mObservers是LiveData观察者的集合
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
//不允许相同的owner,observer组合重复添加
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
//我们的包装类LifecycleBoundObserver还是LifecycleEventObserver
//它也被添加到了Lifecycle的观察者中
owner.getLifecycle().addObserver(wrapper);
}
}
//LiveData观察者的定义
public interface Observer {
void onChanged(T t);
}
代码不多,包含的东西不少。我们提供的观察者observer,在被包装之后,既被添加到了LiveData的观察者集合中,又被添加到了了Lifecycle的观察者集合中。这至少保证了两件事:第一,LiveData的数据变化后,observer可以收到通知;第二,生命周期状态变化时,observer可以收到通知。即LiveData职责的第3、第4两点。
LiveData本身定义的观察者Observer
是很简单的,只有一个onChanged
方法,在LiveData数据发生变化时被调用。但是,如前所述,LiveData最大的特点就是,它与生命周期的紧密关联。其observe
方法包含两个参数,LifecycleOwner
和Observer
,每个Observer
还附带了一个生命周期的拥有者LifecycleOwner
。为了完成前面说的职责3和职责4,需要对Observer
进行包装,以为其增加更多状态,所以才有了ObserverWrapper
,LifecycleBoundObserver
。
public abstract class LiveData {
static final int START_VERSION = -1;
//有多少LiveData的观察者处于“活动”状态
int mActiveCount = 0;
private abstract class ObserverWrapper {
//被包装者,即LiveData原始的观察者
final Observer super T> mObserver;
//观察者是否处于“活动”状态;为原始观察者mObserver增加属性,这也是包装类的意义
boolean mActive;
//每个ObserverWrapper初始时version都被设置为了START_VERSION
int mLastVersion = START_VERSION;
ObserverWrapper(Observer super T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
/**
* ObserverWrapper的主要职责就是:接收来自外部的activeState状态的变化,
* 这里的activeState指的是被包装者 mObserver 是否处于“活动”状态
* 处于“活动”状态的观察者可以接收LiveData数据的变化,否则则不能;
* 以上所说的活动状态指的是当前观察者的活动状态,可以理解为 mObserver 的活动状态,
* LiveData本身也有活动状态,当LiveData从“活动”状态变为“非活动”状态时,其onActive方法会被调用;
* 当LiveData从“非活动”状态变为“活动”状态时,其onInactive方法会被调用;
* LiveData的活动状态取决于它本身的观察者是否至少有一个处于“活动”状态
*/
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
//为LiveData处于活动的观察者计数
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive(); //LiveData中的方法,空实现
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive(); //LiveData中的方法,空实现
}
if (mActive) {
//LiveData中的方法,每当观察者来的“活动”状态时,就会分发LiveData中的数据,
//至于observer中的onChanged方法会不会被调用,还有别的判断,之后再看
dispatchingValue(this);
}
}
}
}
ObserverWrapper的主要职责是处理活动状态的变化,这种活动状态包括观察者的活动状态,和LiveData的活动状态(注意区分两者)。
在本文中,活动状态指的是一种状态,有两种情况,“活动”和“非活动”;“活动”状态指的是前述状态处于“活动”这种情况。
需要注意,activeStateChanged
方法是在外部被调用的,也就是说,有地方监听状态的变化,并负责通知ObserverWrapper,我们之后会看到。
再来看看对ObserverWrapper进一步的包装LifecycleBoundObserver:
public abstract class LiveData {
/**
* 很重要的一点LifecycleBoundObserver实现了LifecycleEventObserver接口,
* 这个接口是对于生命周期事件的观察者,详见Lifcycle源码解析
*/
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer super T> observer) {
super(observer);
mOwner = owner;
}
//生命周期至少处于STARTED状态时,观察者才是“活动”状态
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
//该方法是接口LifecycleEventObserver中的方法
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
//生命周期来到了DESTROYED,则从LiveData中移除原始的观察者mObserver
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
//指的是LiveData中的removeObserver方法
//removeObserver方法会把观察者从LiveData的观察者集合中移除,
//然后还会调用下面的detachObserver方法,从Lifecycle中移除观察者
removeObserver(mObserver);
return;
}
//上面提到的ObserverWrapper中的activeStateChanged方法,
//每当生命周期变化时就调用activeStateChanged
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
//从生命周期观察者中移除
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
}
先来回顾一下子为LiveData添加一个观察者的流程,我们的观察者Observer
被包装成了LifecycleBoundObserver
,然后分别被添加到了LiveData的观察者集合中,和Lifecycle的观察者中。LifecycleBoundObserver
背后其实是两层包装,第一层包装是ObserverWrapper
(可以被添加到LiveData的观察者中),第二层包装是LifecycleBoundObserver
(实现了LifecycleEventObserver
,可以被添加到Lifecycle的观察者中)。
然后再来看LifecycleBoundObserver
的源码,注释中已经写得很清楚了,主要就时两点:
- 生命周期变化时通知活动状态是否处于“活动”中(处于“活动”状态的观察者,并且之前有“积压”的数据未通知时,观察者的
onChanged
方法会被调用) - 生命周期来到DESTROYED时,移除相应观察者(从LiveData和Lifecycle中)
总结一下,LiveData添加观察者的内容:
- 对Observer进行包装
- 将包装后的Observer分别添加到LiveData和Lifecycle的观察者中
- 将生命周期的变化转换为活动状态的变化,并且通知观察者(ObserverWrapper)活动状态的变化
- 生命周期来到DESTROYED时,移除相应观察者(从LiveData和Lifecycle中)
LiveData职责的1、2、4条都得到了验证。下面主要来看LiveData是如何通知观察者数据改变的,并且如何避免重复的通知。也即,LiveData职责的第3、第5两条。
3. LiveData数据的通知
LiveData需要在两种情况下分发数据:
- LiveData本身数据发生变化时
- 某个观察者由于生命周期的变化而变成“活动”状态时
之所以讲分发数据,而不是通知数据的变化,是因为真正的通知数据的变化还取决于其他因素,例如,观察者是否处于“活动”状态,观察者是否已经接收过本次的数据。
改变LiveData的数据需要使用其setValue
或者postValue
方法,取决于是否在主线程修改数据:
public abstract class LiveData {
//数据锁
final Object mDataLock = new Object();
static final int START_VERSION = -1;
//初始时下LiveData处于未设置状态
static final Object NOT_SET = new Object();
//LiveData真正的Data,LiveData的数据
private volatile Object mData;
//通过postValue设置数据
volatile Object mPendingData = NOT_SET;
//LiveData的数据version,用于与观察者的version进行比较,避免重复通知
private int mVersion;
private boolean mDispatchingValue;
private boolean mDispatchInvalidated;
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
/**
* 使用给定value对LiveData初始化
*/
public LiveData(T value) {
mData = value;
mVersion = START_VERSION + 1;
}
/**
* 默认初始化
*/
public LiveData() {
mData = NOT_SET;
mVersion = START_VERSION;
}
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
//切换到主线程去设置数据,ArchTaskExecutor是AAC中使用的线程池,Room也在使用
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
//version增加
mVersion++;
mData = value;
//分发数据的变化
dispatchingValue(null);
}
}
可以看出postValue
方法最终还是调用的setValue
方法,setValue
方法也很简单,增加版本号,设置数据,并且分发数据。
我们来跟进一下dispatchingValue
方法:
public abstract class LiveData {
//initiator如果为null,证明是LiveData的数据发生了变化,要对所有观察者分发数据,
//如果initiator不为null,那说明是因为这个initiator代表的观察者变为“活动”状态,只需要通知这个initiator本身就可以了
void dispatchingValue(@Nullable ObserverWrapper initiator) {
//mDispatchingValue和mDispatchInvalidated两个标志是为了防止在数据分发的时候,LiveData的数据再次发生变化;
//例如,某个观察者onChanged方法内部又调用了setValue方法
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator); //只通知initiator本身
initiator = null;
} else {
for (Iterator, 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) { //非“活动”状态的observer不通知数据的变化
return;
}
// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
//
// we still first check observer.active to keep it as the entrance for events. So even if
// the observer moved to an active state, if we've not received that event, we better not
// notify for a more predictable notification order.
// 这个判断我没有看懂,包括上面的注解本身我也没有看懂,留作一个疑问,有明白的还望告知
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//观察者的version不小于LiveData的version,说明该观察者已经被通知过了,不再通知
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//终于看到了我们observer的onChanged方法被调用
observer.mObserver.onChanged((T) mData);
}
}
LiveData数据分发的脉络还是很清晰的,因为LiveData数据发生变化的,对所有观察者考虑是否通知数据的变化;因为某个观察者变为“活动”状态的,只对该观察者本身考虑是否通知数据的变化。并且通过比较LiveData和观察者(ObserverWrapper)的版本号,来避免重复的通知。LiveData职责的第3、第5两条也得到了验证。
到这里,关于LiveData的源码基本上是分析完了,其中省略了如下一些内容:
- LiveData移除观察者
- 为LiveData添加“永久”的观察者(
observeForever
方法),说是“永久”的观察者,其实就是没有绑定生命周期的观察者,也可以手动移除。 - MutableLiveData
这些内容比较简单,在此略过。
4. LiveData的转换Transformations
上文提到了LiveData的onActive
和onInactive
方法,分别在LiveData变为“活动”和变为“非活动”时被调用,但是在LiveData本身的实现中,onActive
和onInactive
均为空实现。其实,单对于观察LiveData数据的变化而言,确实没有必要实现LiveData本身的活动状态的变化,这两个方法主要是用来自定义LiveData或者对LiveData进行转换的。具体使用场景见Google文档。下面具体分析一下LiveData的转换。
最简单的LiveData的转换的例子就是map,就像RxJava中的map那样。LiveData实现转换的关键是MediatorLiveData类:
//类如其名,中介者LiveData
public class MediatorLiveData extends MutableLiveData {
private SafeIterableMap, Source>> mSources = new SafeIterableMap<>();
/**
* 添加作为“源”的LiveData,和对“源”的LiveData的观察者
* 当“源”LiveData数据变化,并且当前MediatorLiveData处于“活动”状态(拥有“活动”观察者)时,onChanged就会被调用
* 实际上正如类名一样,这实际上起到了中介者的作用,MediatorLiveData传递了“源”LiveData的数据变化,同时我们又可以在onChanged中对“源”LiveData的数据进行转换
*/
@MainThread
public void addSource(@NonNull LiveData source, @NonNull Observer super S> onChanged) {
Source e = new Source<>(source, onChanged);
Source> existing = mSources.putIfAbsent(source, e);
if (existing != null && existing.mObserver != onChanged) {
throw new IllegalArgumentException(
"This source was already added with the different observer");
}
if (existing != null) {
return;
}
if (hasActiveObservers()) {
e.plug();
}
}
/**
* 移除“源”LiveData
*/
@MainThread
public void removeSource(@NonNull LiveData toRemote) {
Source> source = mSources.remove(toRemote);
if (source != null) {
source.unplug();
}
}
@CallSuper
@Override
protected void onActive() {
for (Map.Entry, Source>> source : mSources) {
source.getValue().plug();
}
}
@CallSuper
@Override
protected void onInactive() {
for (Map.Entry, Source>> source : mSources) {
source.getValue().unplug();
}
}
private static class Source implements Observer {
final LiveData mLiveData;
final Observer super V> mObserver;
int mVersion = START_VERSION;
Source(LiveData liveData, final Observer super V> observer) {
mLiveData = liveData;
mObserver = observer;
}
void plug() {
mLiveData.observeForever(this);
}
void unplug() {
mLiveData.removeObserver(this);
}
@Override
public void onChanged(@Nullable V v) {
if (mVersion != mLiveData.getVersion()) {
mVersion = mLiveData.getVersion();
mObserver.onChanged(v);
}
}
}
}
单看MediatorLiveData可能比较懵逼,没事,结合map等转换一起看就明白什么意思了。
public class Transformations {
private Transformations() {
}
/**
* 最简单明了的转换操作
* 传入source “源”LiveData,将其转换为另一种类型的LiveData
* LiveData -> LiveData
*/
@MainThread
@NonNull
public static LiveData map(
@NonNull LiveData source,
@NonNull final Function mapFunction) {
final MediatorLiveData result = new MediatorLiveData<>();
result.addSource(source, new Observer() {
@Override
public void onChanged(@Nullable X x) {
//source的变化会通知到这个方法,我们用mapFunction对我们接收到的数据进行转换
result.setValue(mapFunction.apply(x));
}
});
//返回中介 MediatorLiveData
return result;
}
/**
* 这个方法比较不好理解,可以去看源码中的注释帮助理解
*/
@MainThread
@NonNull
public static LiveData switchMap(
@NonNull LiveData source,
@NonNull final Function> switchMapFunction) {
final MediatorLiveData result = new MediatorLiveData<>();
result.addSource(source, new Observer() {
LiveData mSource;
@Override
public void onChanged(@Nullable X x) {
LiveData newLiveData = switchMapFunction.apply(x);
if (mSource == newLiveData) {
return;
}
if (mSource != null) {
result.removeSource(mSource);
}
mSource = newLiveData;
if (mSource != null) {
result.addSource(mSource, new Observer() {
@Override
public void onChanged(@Nullable Y y) {
result.setValue(y);
}
});
}
}
});
return result;
}
/**
* 直到source数据跟上次的数据不同时才通知
*/
@MainThread
@NonNull
public static LiveData distinctUntilChanged(@NonNull LiveData source) {
final MediatorLiveData outputLiveData = new MediatorLiveData<>();
outputLiveData.addSource(source, new Observer() {
boolean mFirstTime = true;
@Override
public void onChanged(X currentValue) {
final X previousValue = outputLiveData.getValue();
if (mFirstTime
|| (previousValue == null && currentValue != null)
|| (previousValue != null && !previousValue.equals(currentValue))) {
mFirstTime = false;
outputLiveData.setValue(currentValue);
}
}
});
return outputLiveData;
}
}
最初的Transformations类只有map这一个方法,现在又增加了两个,源码也不难理解,核心思想都是拿到“源”LiveData的数据,然后对数据做转换后,再设置给MediatorLiveData,这样通过MediatorLiveData,转换就完成了。
可以看出,LiveData是想模仿RxJava那样的操作符的,但是,LiveData的设计思想跟RxJava差别还是很大的,能实现的操作符非常有限。Transformations的主要作用是,正确传递“源”LiveData的数据变化,并且保证观察者的生命周期变化能传递给“源”LiveData。说白了,就是让MediatorLiveData没有存在感。
5. 隐藏技能
- 如果我们的观察者处于“非活动”状态,他变为“活动”状态后只会收到最新的数据,也就是说LiveData的数据是会“折叠”的。
- 除非你人为的去设置LiveData的数据为null(
setValue(null)
或者postValue(null)
),否则在Observer的onChanged方法中接收到的数据是不可能为null的。如果使用第三方库提供的某些LiveData,在onChanged中判空是有必要的,说不定它用null代表什么特殊的含义。
6. 总结
我们的观察者经过包装后,被添加进LiveData的观察者集合,同时,也被添加到了我们提供的Lifecycle的观察者集合中(如果我们提供了LifecycleOwner的话),这样,无论是LiveData本身的数据发生变化,还是观察者变为“活动”状态时,我们的观察者都会被cue到。但是,只有当我们的观察者处于“活动”状态并且没有被通知过的时候(version低于LiveData的version),Observer的onChanged方法才会被调用。