注册

Android LiveData原理分析

前言

官方介绍:LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。 它有以下的优势:

  • 确保界面符合数据状态
  • 不会发生内存泄露
  • 不会因Activity停止而导致崩溃
  • 不再需要手动处理生命周期
  • 数据始终保持最新状态
  • 适当的配置修改
  • 共享资源

接下来我们通过基本使用,一步一步的探究LiveData是如何实现这些优势的。

使用

创建 LiveData 对象

public class CoursePreviewModel extends ViewModel {

/**
* view状态
*/
private MutableLiveData<List<CoursePreviewBean.DataBean>> mStateLiveData;

public MutableLiveData<List<CoursePreviewBean.DataBean>> viewStateLive() {
if (mStateLiveData == null) {
mStateLiveData = new MutableLiveData<>();
}
return mStateLiveData;
}
}

观察 LiveData 对象

class CoursePreviewActivity : AppCompatActivity() {

// Use the 'by viewModels()' Kotlin property delegate
// from the activity-ktx artifact
private val mViewModel: CoursePreviewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 监听
mViewModel.viewStateLive().observe(this, target -> {
});
}
}

原理分析

这里我们先提出几个问题:

  1. LiveData怎么绑定到应用组件的生命周期呢
  2. 为什么不需要我们手动处理生命周期,为什么不会因Activity停止而导致崩溃
  3. 数据变化又是怎么触发的呢

带着这些问题,我们逐步往里看

一、应用组件生命周期的绑定

当我们需要观察数据变化时,需要调用LiveData的observe接口,这也是LiveData与Activity或Fragment产生关联的地方:

    @MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
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);
}

这个方法需要接收两个参数:

  • LifecycleOwner:生命周期所有者
  • Observer:观察者,用于观察获取变化后的数据

通常我们在Activity或Fragment中使用LiveData,看下androidx包提供的AppCompatActivity和Fragment都是实现了LifecycleOwner接口。所以直接将this作为第一个参数即可。

继续分析上边的observe方法

  • 这里会首先判断是否在主线程执行,假如不是即会抛出异常
assertMainThread("observe");
static void assertMainThread(String methodName) {
if (!ArchTaskExecutor.getInstance().isMainThread()) {
throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
+ " thread");
}
}
  • 假如是应用组件的生命周期已经是destory的状态,即不会继续往下执行
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
  • 通过LifecycleBoundObserver进行真正的逻辑处理,这里我们继续往下走,待会再回头分析这块
  • 判断相同的observer不能被不同的LifecycleOwner处理
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;
}

这里主要用到SafeIterableMap这个结构保存owner和observer的关系:

// put之前先判断是否已经包含了该key,假如是则直接返回相应的value
public V putIfAbsent(@NonNull K key, @NonNull V v) {
Entry<K, V> entry = get(key);
if (entry != null) {
return entry.mValue;
}
put(key, v);
return null;
}
  • 最后,将生命周期所有者与observer绑定起来,这样子observer即可接收到相应的生命周期
owner.getLifecycle().addObserver(wrapper);

可以看到,这里不是直接add传递进来的Observer,而是上边提到的包装了owner和Observer的LifecycleBoundObserver。所以接下来我们好好分析下它:

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) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}

@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}

@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}

可以看到,LifecycleBoundObserver是实现了LifecycleEventObserver接口,而LifecycleEventObserver接口是继承于LifecycleObserver接口的,因此可以看出主要是在LifecycleBoundObserver这里完成生命周期的处理。

二、为什么不需要手动处理生命周期

经过上边的分析,我们发现其实主要的生命周期处理工作是在LifecycleBoundObserver里边完成的。我们继续看它的源码,有这么两个方法:

    @Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}

@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}

我们先看detachObserver,这里明显就是用于解除绑定的。我们找下哪里调用了这个方法:

@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
assertMainThread("removeObserver");
ObserverWrapper removed = mObservers.remove(observer);
if (removed == null) {
return;
}
removed.detachObserver();
removed.activeStateChanged(false);
}

主要是在LiveData的removeObserver,那继续找下该方法的调用。发现又回到了LifecycleBoundObserver本身,不错就是在onStateChanged里边,它会接收生命周期的变化通知,当发现mOwner.getLifecycle().getCurrentState() == DESTROYED即组件处于destory状态时,自动移除相应的观察者,这样子当activity或fragment销毁时,不会再收到相应的事件通知

三、数据变化怎么触发的

我们继续将核心放在LifecycleBoundObserver的onStateChanged方法上。当组件还没销毁,即会继续往下跑activeStateChanged(shouldBeActive());,该方法定义在ObserverWrapper类里边(LifecycleBoundObserver继承于它)

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.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}

当处于活跃状态,即mActive为true时,会走到dispatchingValue(this);。我们继续看

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;
}

核心在于considerNotify方法

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.
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);,这里就会触发数据变化回调。而这里的mObserver即是我们在刚开始传递进来的。

其他

一、observeForever

其实,LiveData除了提供observe用于方法,还提供了一个observeForever方法

@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
wrapper.activeStateChanged(true);
}

这里可以看到,没有跟生命周期绑定,也不再使用LifecycleBoundObserver进行包装,而是使用AlwaysActiveObserver:

private class AlwaysActiveObserver extends ObserverWrapper {

AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}

@Override
boolean shouldBeActive() {
return true;
}
}

AlwaysActiveObserver和LifecycleBoundObserver都继承于ObserverWrapper,但是前者没有重写它的detachObserver方法,因此它不会被自动移除监听。只能通过手动调用removeObserver进行移除。

二、postValue和setValue

两个方法都可以用于更新值,分析下区别:

protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
  1. setValue必须在主线程调用,否则会抛出异常
  2. postValue用于在其他线程更新值,核心在:ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);,这会切回到主线程执行。
  3. 由于postValue是通过handler的消息派发进行处理,而setValue直接设值,因此这种情况需要注意:
// 源码提示
Posts a task to a main thread to set the given value. So if you have a following code executed in the main thread:
liveData.postValue("a");
liveData.setValue("b");

The value "b" would be set at first and later the main thread would override it with the value "a".
  1. 如果在主线程执行已发布任务之前多次调用此方法,则只会调度最后一个值。这个是怎么实现的呢?我们看下postValue里边的处理
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(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);
}
};

第一次,mPendingData的值为NOT_SET,因此postTask为true,而mPendingData为设置的value。直到mPostValueRunnable被执行时,mPendingData才被重新赋值为NOT_SET。假如在主线程执行前,不断的调用postValue,postTask一直为false,mPendingData会被更新到最新设置的值,但是mPostValueRunnable不会被重复执行。


作者:PG_KING
链接:https://juejin.cn/post/7056651781874548773
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册