深入学习 Jetpack 系列的 Android Architecture Components 中的一些列组件,记录一下学习过程,本文是 LiveData 的使用及原理解析,通过一个实际的例子,来体验 LiveData 能给我们带来哪些不一样的功能?最后通过阅读 LiveData 的源码,由浅入深一步一步探索其原理!
LiveData 简介
LiveData 是一种可观察的、粘性的数据存储类。与常规的可观察类不同,LiveData 具有生命周期感知能力,具有生命周期感知的组件,一般指 Activity、Fragment 等,但不局限于此,更泛指实现了 Lifecycle.LifecycleOwner 的组件。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件的观察者。
1.LiveData 的使用
LiveData 一般是和 ViewModel 配合使用的,然而我们目的是分析 LiveData 的原理,所以这里仅展示简单使用,先不介绍配合使用。
class TestLiveDataActivity : BaseActivity() {
private val mStrLiveData = MutableLiveData<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_live_data)
btnUpdate.setOnClickListener {
mStrLiveData.value = "更新值:Update"
}
mStrLiveData.observe(this, Observer { content ->
tvContent.text = content
})
mStrLiveData.observeForever { content ->
tvContent.text = content
}
}
}
1.2 小结
基本使用还是挺简单的,点击按钮后更新 value 值,观察者 Observer 中就会收到回调,并取到更新后的值,并赋值给 TextView 来更新UI。
2.LiveData 原理解析
2.1 MutableLiveData 类
public class MutableLiveData<T> extends LiveData<T> {
public MutableLiveData(T value) {
super(value);
}
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) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
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;
}
owner.getLifecycle().addObserver(wrapper);
}
public interface Observer<T> {
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 statefulObserver = new ObserverWithState(observer, initialState);
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
............
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);
}
statefulObserver.dispatchEvent(lifecycleOwner, event);
popParentState();
targetState = calculateTargetState(observer);
}
if (!isReentrance) {
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);
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() {
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) {
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;
}
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
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");
mVersion++;
mData = value;
dispatchingValue(null);
}
分析2 – LiveData 调用 setValue() 方法,该方法是只能在主线程调用的,来更新最新的值,同时版本号自增 1。
问题:为什么版本号 mVersion 要自增呢? 实际上 mVersion 在这里相当于一个同步标志位,因为 LiveData 在数据分发的时候会根据 Version 比对,是否进行数据的分发,因为不能因为 LiveData 分发一次数据而 Observer 接受到2次、3次或更多。
2.4.1 LiveData ## dispatchingValue() 方法
@SuppressWarnings("WeakerAccess")
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;
}
分析6 和 分析7 – 都将调用 considerNotify() 方法。
2.4.2 LiveData ## considerNotify() 方法
@SuppressWarnings("unchecked")
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);
}
最终调用了 observer.mObserver.onChanged((T) mData) 方法,这个 observer.mObserver 就是我们传入的 Observer 接口,然后调用它的 onChanged() 方法。
如果我们当前环境处在子线程当中,我们必须要用 postValue() 不能使用 setValue()。
2.5 LiveData ## postValue() 方法
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
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;
}
@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) {
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) {
mMainHandler = createAsync(Looper.getMainLooper());
}
}
}
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 = mPendingData;
mPendingData = NOT_SET;
}
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 中缓存的值被更新了,会导致之前的值在未分发之前就被覆盖擦除。
|