深入学习 Jetpack 系列的 Android Architecture Components 中的一些列组件,记录一下学习过程,本文是 LiveData 的使用及原理解析,通过一个实际的例子,来体验 LiveData 能给我们带来哪些不一样的功能?最后通过阅读 LiveData 的源码,由浅入深一步一步探索其原理!
LiveData 简介
LiveData 是一种可观察的、粘性的数据存储类。与常规的可观察类不同,LiveData 具有生命周期感知能力,具有生命周期感知的组件,一般指 Activity、Fragment 等,但不局限于此,更泛指实现了 Lifecycle.LifecycleOwner 的组件。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件的观察者。
1.LiveData 的使用
LiveData 一般是和 ViewModel 配合使用的,然而我们目的是分析 LiveData 的原理,所以这里仅展示简单使用,先不介绍配合使用。
class TestLiveDataActivity : BaseActivity() {
// 声明了一个 MutableLiveData 对象,LiveData 的子类
// 分析1 -- 下面解析
private val mStrLiveData = MutableLiveData<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_live_data)
btnUpdate.setOnClickListener {
// 点击按钮后更新 value 值
// 分析2 -- 下面解析
mStrLiveData.value = "更新值:Update"
}
// 调用了 MutableLiveData 的 observe 方法,observe方法中传入 this 和 Observer
// this 指的是 TestLiveDataActivity 对象,其实是一个 LifecycleOwner。
// Observer 是一个接口
// 分析3 -- 下面解析
mStrLiveData.observe(this, Observer { content ->
// TextView 设置更新后的值
tvContent.text = content
})
// 订阅一个没有关联 LifecycleOwner 对象的 Observer 观察者
// 在这种情况下,Observer 被认为始终处于活动状态,因此当有数据变化时总是会被通知。
// 您可以调用 removeObserver(Observer) 方法移除这些 Observer。
// 因其方法内部将 Observer 封装成 AlwaysActiveObserver,
// 其内部 shouldBeActive() 永远返回 true,所以总是会被通知。具体看后面的解析
mStrLiveData.observeForever { content ->
// TextView 设置更新后的值
tvContent.text = content
}
}
}
1.2 小结
基本使用还是挺简单的,点击按钮后更新 value 值,观察者 Observer 中就会收到回调,并取到更新后的值,并赋值给 TextView 来更新UI。
2.LiveData 原理解析
2.1 MutableLiveData 类
public class MutableLiveData<T> extends LiveData<T> {
/**
* Creates a MutableLiveData initialized with the given {@code value}.
* @param value initial value
*/
public MutableLiveData(T value) {
super(value);
}
/**
* Creates a MutableLiveData with no value assigned to it.
*/
public MutableLiveData() {
super();
}
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
分析1 – MutableLiveData 是一个被观察者,同时也是一个数据持有者,继承自 LiveData 是一个可变的 LiveData,提供了 setValue() 和 postValue() 方法,其中 postValue() 可以在子线程调用。
2.2 LiveData ## observe() 方法
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
// observe 方法调用必须处于主线程,否则会因为断言失败而抛出异常
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
// 首先通过 LifecycleOwner 获取 Lifecycle 对象然后获取 Lifecycle 的 State 值
// 如果是 DESTROYED 直接 return,忽略这次订阅
return;
}
// 把 LifecycleOwner 和 Observer 包装成 LifecycleBoundObserver 对象
// LifecycleBoundObserver 具有生命周期边界的一个对象
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 将观察者存到 SafeIterableMap 中
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// 已经添加过 LifecycleBoundObserver,并且 LifecycleOwner 不是同一个,则抛异常
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
// 将 Lifecycle 和 LifecycleBoundObserver 观察者之间建立订阅关系
// 分析4 -- 下面解析
owner.getLifecycle().addObserver(wrapper);
}
public interface Observer<T> {
/**
* Called when the data is changed.
* @param t The new data
*/
void onChanged(T t);
}
分析3 – this 指的是 TestLiveDataActivity 对象,其实是一个 LifecycleOwner。因为我们的 Activity 默认实现了 LifecycleOwner 接口。
Observer 是一个接口,里面有一个方法 onChanged(),当数据改变时会调用该方法。
上面的步骤,注释写的很详尽,最后将 Lifecycle 和 LifecycleBoundObserver 观察者之间建立订阅关系。
那么接下来就是分析,什么时候通知?怎么通知的?具体的流程是什么?。
分析4 – owner.getLifecycle() 方法返回的是 LifecycleRegistry,具体为何是 LifecycleRegistry,可以看这篇 Jetpack Lifecycle 使用及原理解析;
2.3 LifecycleRegistry ## addObserver() 方法
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
// 初始状态
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
// 通过 ObserverWithState 将观察者和状态进行包装
// 为什么要进行包装 ObserverWithState 呢?
// 主要是为了方便的分发当前宿主的生命周期状态给每个 Observer
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
// 将包装类放到 FastSafeIterableMap<LifecycleObserver, ObserverWithState> 中
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
............
// 将状态进行对齐,在添加观察者的时候,可能是在任何状态的时候进行添加的,
// lifecycle 需要将这个状态进行对齐。例如我们在 onResume 的回调中添加了观察者,
// 此时我们的观察者就收到依次收到 onCreate,onStart,onResume 的回调。
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
pushParentState(statefulObserver.mState);
final Event event = Event.upFrom(statefulObserver.mState);
if (event == null) {
throw new IllegalStateException("no event up from " + statefulObserver.mState);
}
// 分析5 -- 下面解析
statefulObserver.dispatchEvent(lifecycleOwner, event);
popParentState();
targetState = calculateTargetState(observer);
}
if (!isReentrance) {
// we do sync only on the top level.
// 同步状态
sync();
}
mAddingObserverCounter--;
}
分析5 – 这里 statefulObserver.dispatchEvent() 方法,调用到 ObserverWithState.dispatchEvent() 方法。
2.3.1 LifecycleRegistry 内部类 ObserverWithState ## dispatchEvent() 方法
static class ObserverWithState {
State mState;
LifecycleEventObserver mLifecycleObserver;
ObserverWithState(LifecycleObserver observer, State initialState) {
mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
mState = initialState;
}
void dispatchEvent(LifecycleOwner owner, Event event) {
State newState = event.getTargetState();
// 比较添加的观察者和当前生命周期状态取更小的那个状态值
mState = min(mState, newState);
// 因为 Lifecycling.lifecycleEventObserver() 方法中传参的类型是 LifecycleBoundObserver
// LifecycleBoundObserver 实现了 LifecycleEventObserver
// 所以这里 mLifecycleObserver 就是传进来的 LifecycleBoundObserver
mLifecycleObserver.onStateChanged(owner, event);
// 更新状态
mState = newState;
}
}
2.3.2 LiveData 内部类 LifecycleBoundObserver ## onStateChanged() 方法
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
// 判断了只有当前宿主的生命周期是大于 STARTED 这个状态的时候才代表宿主是活跃的
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
if (currentState == DESTROYED) {
// 获取 Lifecycle 对象然后获取 Lifecycle 的 State 如果为 DESTROYED
// 则移除观察者,在 Activity、Fragment的生命周期走到 onDestroy 的时候
// 就会取消订阅,避免内存泄漏。
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
// 生命周期组件状态变更回调
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
可以看到 LifecycleBoundObserver 实现了 LifecycleEventObserver,LifecycleEventObserver 里面有个非常重要的方法 onStateChanged() 方法,这里不贴代码了,跟进去一看就明白了。
onStateChanged() 方法是指宿主生命周期的变化,里面有两个参数 ,第一个参数是指我们的宿主,第二个参数 Lifecycle.Event,是指宿主的生命周期。宿主的每个生命周期的改变都会回调到 LifecycleBoundObserver 类中的 onStateChanged() 方法中。
在 onStateChanged() 方法中判断了,如果当前宿主的生命周期状态是销毁状态,则自行反注册Observer,避免内存泄漏,否则的话调用 activeStateChanged() 方法回调状态的变更,参数是 shouldBeActive() 方法的返回值。
2.3.3 LiveData 内部类 ObserverWrapper ## activeStateChanged() 方法
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;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
// 更新活跃的观察者数、方法内部会根据 previousActiveCount 和 mActiveCount 值
// 判断活跃的观察者数是从0变为1,还是从1变为0
// 分别对应调用 onActive() 和 onInactive() 方法
// 这是 LiveData 预留的两个回调方法
// 当 LiveData 首次注册一个观察者对象时会调 onActive() 方法,在方法中可以做初始化操作
// 当最后一个观察者被移除时会调 onInactive() 方法,在方法中可以做反注册清理的操作
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
// newActive 是 true,即宿主是活跃的,则会走到 dispatchingValue() 方法
dispatchingValue(this);
}
}
}
如果我们传的 newActive 是 true,则会走到 dispatchingValue() 方法,进行数据的分发,2.4.1节会对该方法继续进行解析。
2.3.4 小结
Activity、Fragment 等实现了 Lifecycle.LifecycleOwner 的组件的生命周期改变的时候,并且活跃时会回调观察者 Observer 的 onChanged() 方法。
问题:LiveData 数据更新后如何通知到回调方法?
2.4 LiveData ## setValue() 方法
@MainThread
protected void setValue(T value) {
// 判断线程是否是主线程
assertMainThread("setValue");
// 版本号自增 1
mVersion++;
// value 赋值给 mData
mData = value;
dispatchingValue(null);
}
分析2 – LiveData 调用 setValue() 方法,该方法是只能在主线程调用的,来更新最新的值,同时版本号自增 1。
问题:为什么版本号 mVersion 要自增呢?
实际上 mVersion 在这里相当于一个同步标志位,因为 LiveData 在数据分发的时候会根据 Version 比对,是否进行数据的分发,因为不能因为 LiveData 分发一次数据而 Observer 接受到2次、3次或更多。
2.4.1 LiveData ## dispatchingValue() 方法
@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
// 分析6 -- 下面解析
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
// 分析7 -- 下面解析
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
分析6 和 分析7 – 都将调用 considerNotify() 方法。
2.4.2 LiveData ## considerNotify() 方法
@SuppressWarnings("unchecked")
private void considerNotify(ObserverWrapper observer) {
// 判断数据观察者是否活跃,如果当前不活跃则不分发
if (!observer.mActive) {
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.
// 判断当前宿主的生命周期是否大于 STRATED 如果不大于将当前 observer 状态更改为 false
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// 判断数据观察者的版本值是否 >= 最新版本,是,说明数据是最新的,无需更新
// 只有当 mLastVersion 小于最新版本 Version,才会继续分发
if (observer.mLastVersion >= mVersion) {
return;
}
// 更新数据观察者中的版本值
observer.mLastVersion = mVersion;
// 调用 observer 的 onChanged 方法,并将 mData 传递进去
observer.mObserver.onChanged((T) mData);
}
最终调用了 observer.mObserver.onChanged((T) mData) 方法,这个 observer.mObserver 就是我们传入的 Observer 接口,然后调用它的 onChanged() 方法。
如果我们当前环境处在子线程当中,我们必须要用 postValue() 不能使用 setValue()。
2.5 LiveData ## postValue() 方法
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
// 若第一次调用时,mPendingData == NOT_SET,则 postTask 为 true
// 若短时间内,第二次调用了 postValue,但第一次调用时 post 到主线程的 Runnable
// 的 run() 方法还没执行,即 mPendingData 还未重置为 NOT_SET
// 那么 postTask 为 false,将会直接 return,不会再 post Runnable 到主线程
// 但 mPendingData 的值已经被第二次 postValue() 方法传入的新值所覆盖擦除
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
// 分析8 -- 下面解析
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
问题:为什么连续两次调用 postValue() 只有最后一次的值返回?丢了一个数据
当第一次调用 postValue() 时,mPendingData == NOT_SET,则 postTask 为 true,ArchTaskExecutor 将 post 一个 Runnable 到主线程,然后调用 setValue() 更新 LivaData 的值;若短时间内,第二次调用了 postValue(),但第一次调用时 post 到主线程的 Runnable 的 run() 方法还没执行,存在延迟,即 mPendingData 还未重置为 NOT_SET,那么 postTask 为 false,将会直接 return,不会再 post Runnable 到主线程,但 mPendingData 的值已经被第二次 postValue() 方法传入的新值所覆盖擦除,所以只有最后一次的值返回。
2.5.1 ArchTaskExecutor 类
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public class ArchTaskExecutor extends TaskExecutor {
private static volatile ArchTaskExecutor sInstance;
@NonNull
private TaskExecutor mDelegate;
@NonNull
private TaskExecutor mDefaultTaskExecutor;
private ArchTaskExecutor() {
mDefaultTaskExecutor = new DefaultTaskExecutor();
mDelegate = mDefaultTaskExecutor;
}
/**
* Returns an instance of the task executor.
* @return The singleton ArchTaskExecutor.
*/
@NonNull
public static ArchTaskExecutor getInstance() {
if (sInstance != null) {
return sInstance;
}
synchronized (ArchTaskExecutor.class) {
if (sInstance == null) {
sInstance = new ArchTaskExecutor();
}
}
return sInstance;
}
@Override
public void postToMainThread(Runnable runnable) {
// DefaultTaskExecutor 的 postToMainThread
mDelegate.postToMainThread(runnable);
}
}
分析8 – ArchTaskExecutor 使用代理模式实现了一个内部的线程池 DefaultTaskExecutor 提供使用,同时支持切换主线程的功能。其中如果使用者没有设置自己的 TaskExecutor,那么 ArchTaskExecutor 将会使用 DefaultTaskExecutor 作为默认实现的线程池。
2.5.2 DefaultTaskExecutor ## postToMainThread() 方法
@Nullable
private volatile Handler mMainHandler;
@Override
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
// 使用主线程的 Looper 创建一个 Handler,因此可以切到主线程执行
mMainHandler = createAsync(Looper.getMainLooper());
}
}
}
//noinspection ConstantConditions
// 主线程 Handler 将一个 Runnable post 到 主线程
// 最后 Runnable 的 run() 方法得到执行
mMainHandler.post(runnable);
}
2.5.3 LiveData ## mPostValueRunnable
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
// 新值赋值到 newValue
newValue = mPendingData;
// mPendingData 重新赋值为 NOT_SET
mPendingData = NOT_SET;
}
// 最后调用 setValue() 方法
setValue((T) newValue);
}
};
postValue() 方法其实最终调用也是 setValue() 方法,然后和 setValue() 方法走的流程就是一样的了,setValue() 方法前面已经分析过。
2.5.4 小结
LiveData 调用 setValue()、postValue() 方法,最后会回调观察者 Observer 的onChanged方法。
2.6 LiveData 订阅、分发流程
3.LiveData 总结
3.1 LiveData 是怎样通知值分发?
- 值变更,如调用 setValue()、postValue() 方法主动进行值的更新,后续会调用观察者 Observer 的onChanged方法。
- 实现了 Lifecycle.LifecycleOwner 的组件的生命周期状态的流转,且观察者处于活跃状态。
3.2 LiveData 为什么只会将更新通知给活跃的观察者,非活跃观察者不会收到更改通知?
- 如果使用的是 observe() 方法来订阅观察者,由上面的源码分析可知,只有活跃的观察者可以收到。
- 如果使用的是 observeForever() 方法来订阅一个跟生命周期无关的观察者,那么数据变化时所有的观察者都可以收到。
4.LiveData 其它用法
- 数据共享:单例实现 LiveData 可以多个 Activity 或 Fragment 获取同一个 LiveData 对象,实现相关数据共享。
- 数据修改:通过 Transformations.map 将 LiveData 的数据进行修改,将修改后的数据更新通知给观察者。
- 数据切换:Transformations.switchMap 可根据不同条件返回不同的 LiveData。
- 多数据源:利用 MediatorLiveData 来合并多个 LiveData 数据源,只需定义一个 Observer 观察者,任一数据源发生改变均会通知到观察者 Observer。
上面的用法没有给出例子,篇幅太长了,后面可以单独记录。
5.LiveData 存在的问题及解决
5.1 LiveData 粘性事件
粘性事件就是说,LiveData 先发送数据,再进行订阅 Observer 观察者,但是这个后订阅的观察者 Observer 也会收到之前发送的数据。
原因:LiveData 通过 setValue() 发送数据时,上面2.4节分析过,mVersion 会自增 1,mData 会记录发送的数值。添加观察者,引起生命周期组件状态变化,进而会进行通知值分发,由于使用观察者创建的 ObserverWrapper 的 mLastVersion 为默认值 -1,小于当前 mVersion 的值,所以会触发观察者 Observer 的 onChanged() 方法,即触发值更新。
解决方案:关于 LiveData 粘性事件所带来问题的解决方案
还有一种更加彻底的解决方案,那就是不用 LiveData,转而使用 Kotlin-Flow,这个后面继续学习探索,然后再分享。
5.2 LiveData 会丢失数据吗?
在高频数据更新的场景下使用 LiveData.postValue() 时,会造成数据丢失。因为设值和分发值是分开执行的(2.5节有分析),存在延迟,值先被缓存在变量 mPendingData 中,再向主线程 post 一个分发值的任务 Runnable。在这个延迟期间,再调用一次 postValue() 方法,变量 mPendingData 中缓存的值被更新了,会导致之前的值在未分发之前就被覆盖擦除。