JetPack架构---LiveData特性、原理

一、LiveData的概念与优势

官网介绍LiveData的概念是这样的:

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

归类的说,它有三个特点:

1、它是一个数据存储器类,能持有数据;

2、它可被观察者观察,当存在观察者时,它的数据变化会通知到观察者;

3、它能感知应用组件的生命周期;

它的上面这些特性,结合在一起,有以下的优势:

1、界面数据根据LiveData的数据而变化,数据始终保持最新状态

LiveData 遵循观察者模式。当生命周期状态或者本身数据发生变化时。会通知到相应的观察者。

如果生命周期从活跃状态变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。

2、不会发生内存泄露、不会因 Activity 停止而导致崩溃、不再需要手动处理生命周期

通常的做法,是向LiveData中传入Lifecycle。当LiveData绑定Lifecycle后,LiveData的数据只会在组件生命周期的onStart后,才会被组件感知,当组件的生命周期到了onDestroy后,会在LiveData内部移除观察,不再接受数据。因此不会发生泄漏、也不需要手动处理生命周期,当然也不会因此导致activity的崩溃。

3、封装后的LiveData,可做为EventBus、RxBus的替代。可以很方便的提供数据传递以及项目中的响应式编程。

您可以使用单例模式封装 LiveData ,以便在应用中使用它。

(1)网络数据的获取,通过LiveData获取网络信息 ,然后任何观察者只需观察 LiveData对象,都能感知到数据变化

(2)本地数据的传递。将需要传递的数据用LiveData修饰,在多个页面间,观察者观察同一个LiveData对象。当某个页面上通过修改LiveData的对象时,其他观察者得到通知,实现数据传递。

二、LiveData的原理分析

1、添加依赖

第一种方式,如果是新工程,可以直接在创建工程时,在android studio中勾选androidx选项,会自动带入如下依赖即可。

implementation 'androidx.appcompat:appcompat:1.1.0'

第二种方式,如果是旧工程升级,可以在工程的build中,添加以下依赖:

 def lifecycle_version = "2.2.0"
 // LiveData
 implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"

2、LiveData特点简说

根据前面提到的LiveData的三个特性,LiveData持有数据、可被观察、感知生命周期,我们分别说明

(1)持有数据,是一个数据存储类。

LiveData本身是一个抽象类,并且是顶层类。在android中的定义是这样的:

public abstract class LiveData{}

抽象类,我们无法直接使用,android为此也给我们提供了一个可用的LiveData的继承类:MutableLiveData,就是可变的LiveData。它的结构简单,也是我们日常用的最多的LiveData的实现类,如下:

public class MutableLiveData extends LiveData {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

MutableLiveData提供一个泛型,供传入对象类型,在经过posValue或者setValue后,LiveData中将会把该对象赋值给mData。

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

mData是LiveData的一个局部变量,所以此时,LiveData是一个数据存储类。

(2)LiveData可被观察

LiveData提供了一类方法:observe,包括observe和observeForever。这个方法供外部传入观察者,当LiveData数据发生变化或者LiveData绑定的组件生命周期发生变化的时候,会通过observe的回调方法,通知观察者。

其中observe方法的入参中是一个含有生命周期的LifecycleOwner型组件对象和观察者本身,所以使用该方法订阅观察,会与组件的生命周期相关。

//observe方法订阅,与生命周期相关
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
        ....
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        owner.getLifecycle().addObserver(wrapper);
}

observeForever方法的入参只有观察者本身,不与生命周期关联。

//observeForever方法与生命周期无关
public void observeForever(@NonNull Observer observer) {
        ...
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        wrapper.activeStateChanged(true);
}

(3)感知组件生命周期

这个就是通过observe方法订阅而来的功能。方法中传入LifecycleOwner,并将该观察者observer添加到了owner.getLifecycle()中。当owner的生命周期发生改变时,会调用LifecycleBoundObserver这个包装类的onStateChanged方法。

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer observer){
            super(observer);
            mOwner = owner;
        }

        ...
        //组件生命周期发生变化时,会调用该方法
        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            //该方法会执行后续的observer的onChange回调
            activeStateChanged(shouldBeActive());
        }
       ...
    }

3、LiveData原理分析

原理分析,我们从LiveData给我们的入口开始。LiveData对外提供的方法,我们用到的有设置数据的postValue、setValue以及订阅的observe类型方法。

这里将通过三条路线,来分析LiveData的实现:1、postValue/setValue  2、observe  3、生命周期变化

由简入难,先从MutableLiveData的postValue开始:

(1)postValue在MutableLiveData中调用父类postValue方法。过程如下方所示:

//postValue任务
private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            //锁
            synchronized (mDataLock) {
                //将临时数据传给newValue
                newValue = mPendingData;
                //mPendingData恢复初始值,等待下一次的postValue任务
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            //最终通过setValue设置内容
            setValue((T) newValue);
        }
};

...

protected void postValue(T value) {
        //标识是否有post的runnable在执行,首次默认是false
        boolean postTask;
        //锁,保证postValue设置的内容的顺序性
        synchronized (mDataLock) {
            //mPendingData初始值就是NOT_SET,当mPendingData == NOT_SET时,表示正在执行 
            //postValue
            postTask = mPendingData == NOT_SET;
         
            mPendingData = value;
        }
        //当此时,如果有其他postValue执行到此处,因为前面赋值mPendingData = value,postTask为 
        //false,阻塞执行。可以在端上同一时间,发起100笔postValue实验,能够执行后续runnable的将不 
        //足100次
        if (!postTask) {
            return;
        }
        //将postValue的runnable放到主线程执行
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

(2)postValue最终执行的还是setValue方法,setValue方法就是在主线程上,设置内容。

@MainThread
    protected void setValue(T value) {
        //限制只有主线程可以使用setValue,否则报错
        assertMainThread("setValue");
        //数字累加1
        mVersion++;
        //实际设置内容
        mData = value;
        //如有观察者,通过下方语句会触发回调
        dispatchingValue(null);
}

(3)dispatchingValue方法如何触发回调

//ObserverWrapper入参是针对Observer的一个装饰包装,此时传入null
void dispatchingValue(@Nullable ObserverWrapper initiator) {
        //(1)控制状态
        //mDispatchingValue 默认为false,表示未开始分发。
        //此处添加该判断,是为了判断分发过程中,是否有新的分发请求进入
        if (mDispatchingValue) {
            //如在下方的分发事件执行过程中,有新的请求进入,则将mDispatchInvalidated(分发无效标 
            //识)置为true,会让下发的分发循环重新执行,重新分发一次新的数据

            mDispatchInvalidated = true;
            return;
        }
      
        //(2)分发
        //分发状态置为true
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                //此时initiator为null,执行遍历分发操作
                for (Iterator, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    //实际的分发任务在此处执行
                    considerNotify(iterator.next().getValue());
                    //如果分发过程中,有新的请求调用了dispatchingValue方法,分发无效标识 
                    //mDispatchInvalidated会在前面被置为true,跳出for循环,且此时while的条件为 
                    //真,会重新执行do..while循环,重新将最新的数据分发下去
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        //分发任务全部执行完毕,则恢复默认值
        mDispatchingValue = false;
    }

(4)实际分发任务执行considerNotify

private void considerNotify(ObserverWrapper observer) {
        //当观察者不存在或者未激活时,不做操作
        if (!observer.mActive) {
            return;
        }
        //当观察者不处于活动时,不发生回调
        if (!observer.shouldBeActive()) {
            //更新livedata内部的某些状态
            observer.activeStateChanged(false);
            return;
        }
        //版本判断
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        //回调数据
        observer.mObserver.onChanged((T) mData);
    }

到此,postValue与setValue的流程就告一段落。在最后的数据回调前,存在判断观察者是否存在,如不存在是不会发生回调的。

因此,这就要求我们需要给LiveData添加观察者。

以上是我们postValue与setValue流程告一段落,那么后续就来看一下observer是如何注册到LiveData中

(5)观察者observer的添加

在页面上给LiveData添加观察者,调用到LiveData的observe方法

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
        //主线程限定
        assertMainThread("observe");
        //组件的生命周期如果是DESTROYED,直接返回
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        //observer包装类,绑定组件与观察者
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        //判断该观察者是否已存在
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        //同一个observer 不能添加到不同的组件的生命周期中
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        //将observer包装类,添加到组件的生命周期
        owner.getLifecycle().addObserver(wrapper);
    }

该方法传入LifecycleOwner的实现(一般情况下就是activity、fragment或者service)以及观察者observer-->判断是否在主线程-->如果是主线程,判断生命周期是否处于DESTROYED,如果不是则继续-->将owner与observer传入装饰包装类LifecycleBoundObserver中-->最后把这个observer包装类添加到组件的生命周期上。

下方式包装类的具体内容:

//GenericLifecycleObserver 接口是与传入的LifecycleOwner中的生命周期相对的
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() {
            //判断此时的生命周期是否已处于STARTED后(也就是onStart后)
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            //当组件的生命周期发生变化时,会主动回调该方法
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                //生命周期销毁时,移除该观察者
                removeObserver(mObserver);
                return;
            }
            //生命周期变化,且非DESTROYED时,继续操作
            activeStateChanged(shouldBeActive());
        }

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

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

以上这个LifecycleBoundObserver类,做了LifecycleOwner与observer做了绑定。当传入的组件生命周期变化,触发onStateChanged该方法。至此,前面提到的三条路线已经解析完成。这个就是LiveData的主要流程。

 

4、懂的更多

LiveData源码解析中,有哪些内容是你需要注意的?

(1)postValue中,为什么要有mPendingData?

         postValue在传输数据的过程中,会经过两段操作。mPendingData作为临时存储数据的变量,是为了保证postValue多次、同           时被调用时的线程安全。

(2)对一个LiveData数据,同时做setValue与postValue,结果会是如何?

         如果再同一时刻,对同一LiveData数据,做了setValue与postValue操作。最终页面刷新的数据,会是postValue中的数据。此           处注意不要这么操作。

(3)setValue/postValue过程中的dispatchingValue的逻辑巧用。

         两个标识mDispatchingValue与mDispatchInvalidated,在入口判断与do...while中的循环逻辑,对分发过程中有新的数据需要           分发时,做了一次重新分发。

(4)onActive 与 onInactive的调用时机是什么样的?

        onActive是在观察者从0到1的情况下,被调用。onInactive是在观察者从1到0的情况下被调用。

(5)observeForever与observe的区别是什么?

        observeForever与生命周期无关。当使用该方法添加观察者后,不会与生命周期相关,如果无需使用的时候,需要手动                    remove。这与通常的观察者模式是类似的。

(6)为什么LiveData会带有粘性特制?

       假设在activity1中,有定义LiveData变量a,此时你并没有在该页面添加观察者,而是在activity2的onCreate中添加观察者。

       当你在activity1,setValue或者postValue后,跳转到activity2,你会发现activity2中的观察者的回调起效了。

       这就是类似EventBus的粘性事件,为什么会这样?仔细看源码,你会发现因为当你打开activity2,并且添加了观察者时,符合

       了:生命周期变动 并且 observer.mLastVersion < mVersion ,引发了onChange。

        如果不需要粘性事件,有两种方式:1、反射方式,在每次observe的时候,设置observer.mLastVersion = mVersion,这样首          次observe将不会再回调。2、YourLiveData继承LiveData,重写observe方法,并observer.mLastVersion = mVersion,在程序          中使用你自己的YourLiveData。

 

总结的说:当你将一个对象用LiveData包装后,你可以通过postValue/setValue修改该对象的值,该值会反应在与LiveData的观察者上。以此可以实现数据驱动UI。LiveData中含有生命周期的判断,会在合适的时候,判断是否解除观察者订阅,避免内存泄漏等。这是针对android的一个很好的架构组件!后续将介绍如何使用。

       

 

你可能感兴趣的:(Android技巧)