Jetpack源码解析(二):LiveData解析

JetPack作为Google官方推荐的一套标准化开发套件,很值得去使用和学习。

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

基本使用

LiveData本质是一个①遵循生命周期、②可供观察的存储类。

使用姿势1 使用姿势2
正常使用.png
黏性使用.png

乍一看和我们之前学的EventBusRxBus之类的事件总线很像,不就是个观察者模式嘛。姿势2不就是反映出黏性的状态嘛。

事实也是如此。

不过它具有生命周期感知能力LiveData 只会将更新通知给活跃的观察者。为观察 LiveData对象而注册的非活跃观察者不会收到更改通知。

Google官方不建议我们这样直接在Activity中使用,而是将LiveData放在ViewModle中,Activity中只负责监听及变化后的处理事件。以构建成MVVM架构。

源码解析

image-20201218114150694.png

MutableLiveData继承自LiveData,直接看LiveDataobserve()方法。

observe(owner,observer)

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer 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);
}

之前说过,LiveData 仅更新处于活跃生命周期状态的应用组件观察者,这里的活跃状态具体指的是STARTRESUME

首先是必须要在主线程执行,判断生命周期状态是否活跃;然后new一个LifecycleBoundObserver命名为wrapper,将其作为VALUE,以传进来的observer为KEY,存入mObservers中。

然后将wrapper放入生命周期的监听中。wrapper实现了LifecycleEventObserver接口,所以wrapper放进去后接着就会调用wrapper中的onStateChanged方法【这一句内容属于Lifecycle知识点,详见Lifecycle解析】。

wrapper.onStateChanged

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

@Override
boolean shouldBeActive() {
    return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

判断了下生命周期是否活跃,然后走向了activeStateChanged( )

这里传入的布尔值是判断生命周期状态:当前状态在STARTED之前,false; 在STARTED状态之后,true。

说明只有在STARTEDRESUME状态时会传true进去,印证了之前说的 “活跃状态具体指的是STARTRESUME

//这个方法是在抽象类`ObserverWrapper`中。
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);
    }
}

这个方法中,先将传进来的newActive赋值给mActive

mActiveCount表示活跃状态下 obs的数量;wasInactive(为true)表示之前活跃状态下没有obs;

mActivetrue表示当下处于活跃状态,并且你传给了我个obs。

所以mActive为true的时候,mActiveCount要+1;为false时,mActiveCount要-1。注意这里mActiveCount发生了改变!!

然后判断,如果改变之前没有obs活跃 && 传来的obs即将变活跃,那就要onActive();

如果 改变之后依然没有obs活跃 && 传来的obs也不会变活跃,那就onInactive();

当然这两个方法都是空的,需要用户自己去写。

说人话就是:当活跃的数量0-->1时,执行onActive();由1-->0时,执行onInactive()

最重要的其实是下一句:如果现在是活跃状态,我收到了obs,所以要执行下一步操作了。

dispatchingValue(wrapper)

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, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

这两个布尔值,emmm,看的有点绕。再看这个do while,这循环怎么这么怪?

//第一次A,B = false
 if(A){
     B = true;
     return
 }
A = true
do{
    B = false
        ...//不会改变B的代码
}while(B)

WTF??一脸黑人问号?这种循环能跑到第二圈?这种循环要是能循起来,我当场把显示器吃掉!!

不管了,重点看do while中的代码,传进来wrapper是不为空的,走considerNotify方法,

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData);
}

一些列判断之后,如果未被return,则执行wrapper.mObserver.onChanged()方法。

当然,第一次 observer.mLastVersionmVersion都是初始值-1,所以不会执行到此。除非mVersion变了...

大的流程走通了,再看看setValue方法。

setValue

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

版本++,存储data,然后再dispatchingValue(null);

等等,这里也进到了dispatchingValue,也就是说dispatchingValue中可能出现多个线程同时访问进去的情况。这样一来之前看不懂的那两个布尔值和一个长得奇怪的do while循环就说得过去了。

Snipaste_2020-12-18_16-36-26.png

这种情况下,循环就循环起来了。

image-20201218170327040.png

咳咳,我们继续。dispatchingValue方法中有一个针对null的判断,这时候传进来的initiator为空,走else的方法。把mObservers遍历一遍,然后依次执行considerNotify(iterator.next().getValue());

如果大家记性不太好的话,我帮大家回忆一下:

LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);

所以getValue方法中得到的就是我们在observe方法中初始化的wrapper。

再看considerNotify

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData);
}

这次进入这个方法的时候有一点不一样,我们在setValue方法中版本++了,所以这个时候mVersion大于mLastVersion了,这个时候才会执行observer.onChanged方法。

mVersion的意义就在这里体现出来了。

如果你先setValue(版本++),然后再observer(),onChanged依然会被触发。这就是所谓的黏性事件。也就是说黏性是在源码中写死了的,不支持像EventBus那般可进行配置。你想不黏性都不行。

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() {
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        //noinspection unchecked
        setValue((T) newValue);
    }
};

postValue也一样,通过一个mPostValueRunnable,最后转到了SetValue方法。

总结

LiveData的作用其实是事件的分发,其实现原理是基于发布/订阅者模式,但是LiveData和传统的EventBus、RxBus这类事件总线又不太一样。

Google对其在功能上加以限制,几乎只有set/post和observe这三个方法;而上述Bus框架理论上可以在代码的任意一处进行分发,在代码的其他地方进行任意调用,虽然灵活,但无形中增加了管理成本,尤其是当项目日益庞大的时候,若项目中的Bus管理不善,发送和接收的事件(event)将会泛滥成灾,造成不可预期的后果。

而LiveData,可以通过和ViewModle的配合,完美规避这些问题,使事件的传递更加纯粹 和 易于管理。

同时,LiveData生命周期感知能力也避免了由于生命周期的变化带来的内存泄露等问题。

当然,你也完全可以利用LiveData将其封装成LiveDataBus,实现相似的事件总线框架,但是这有违Google的初衷,Google开发团队的初衷是让我们使用LiveData+ViewModle的模式来管理数据,这才是Google团队认为的最佳做法。


最后,关于LiveData的粘性设计可能带来的BUG和解决方案,我会另开一篇文章详谈,不在此赘述。

你可能感兴趣的:(Jetpack源码解析(二):LiveData解析)