美文网首页
深入理解AAC架构 - LiveData 使用以及整体机制源码

深入理解AAC架构 - LiveData 使用以及整体机制源码

作者: 七零八落问号 | 来源:发表于2020-02-25 21:12 被阅读0次

    LiveData的主要工作:

    一个带有生命周期侦测特性的数据持有者。
    AAC架构中的实际数据持有者,通常存放在ViewModel中,通过ViewModel脱离生命周期对数据的影响。
    本身机制是观察者模式,在数据更新时,会通知所有已激活 (或根据需求通知未激活) 的观察者最新数据。
    由于生命周期侦测的特性,LiveData在添加观察者时,要求观察者附带其生命周期所在的LifecycleOwner


    LiveData的主要类:

    • LiveData
      核心功能类,抽象类。
      LiveData模块的主体,模块的基本实现都在该类中。

    • MutableLiveData
      核心功能类
      LiveData的非抽象子类,只是把postValue()setValue()的访问权限扩大成public并可实例化。

    • Observer
      核心功能类,观察者接口。

    • LiveData$ObserverWrapper
      LiveData的内部类,观察者实例的容器类的抽象父类。
      注册到LiveData的观察者,被会ObserverWrapper的子类包装,再加入观察者列表。
      维护了对应观察者的:
      1- 当前数据版本
      2- 当前观察者的激活状态
      同时负责通知LiveDataonActive()onInactive()

    • LiveData$AlwaysActiveObserver
      ObserverWrapper的一个子类。
      通过LiveData.observeForever()传入的观察者将会被此类包装。
      被该类包装的观察者不关注生命周期,不受生命周期影响,并且激活状态永久为true
      使用该方法时应该注意手动释放观察者,以避免内存泄漏。

    • LiveData$LifecycleBoundObserver
      核心功能类ObserverWrapper的一个子类。
      通过LiveData.observe()传入的观察者将会被此类包装。
      该类是LiveData生命周期监管的核心,该类实现了LifecycleEventObserver接口,并在创建后注册到观察者对应的生命周期内,以实现激活状态管理和主动释放。

    • MediatorLiveData
      MutableLiveData的一个子类。
      该类除了LiveData的功能外,允许对多个LiveData的进行观察。
      简单的描述:
      MutableLiveData会把需要观察的LiveData和对应的Observer封装为一个Source,自身则维护着Source列表。
      MutableLiveData激活时,遍历Source列表,以AlwaysActiveObserver的形式对需要观察的LiveData进行注册。
      MutableLiveData失去激活时,则自动移除Source列表中所有LiveData注册。
      任意LiveData数据更新时,根据需求,决定是否对自身进行维护或更新,即实现了对任意个LiveData的数据更新事件进行管理。

    • Transformations
      工具类,不可实例化。
      用于实现LiveData的数据进行一定的流处理操作,例如发布控制,类型转换等。
      工具类的方法,实际上是通过MediatorLiveData对传入的LiveData进行观察,当LiveData更新数据时,数据会传入的用户定义的方法中进行控制或转换,然后选择性通过MediatorLiveData.setValue()发布处理后的数据。
      工具提供了3个方法:(livedata-2.2.0)
      1- map
      使LiveData<X>通过Function转换为LiveData<Y>
      即:LiveData<X>数据更新 - > Function转换 -> MediatorLiveData<Y>数据更新
      ..
      2- switchMap
      根据LiveData<X>的数据,根据Function返回需要观察的LiveData<Y>
      即:LiveData<X>数据更新 - > Function选择数据源 -> MediatorLiveData<Y>数据源更新。
      ..
      map对比,map的数据源直接来自LiveData<X>
      switchMap的数据源是Function返回的LiveData<Y>LiveData<X>对于switchMap来说只是个数据源控制器。
      ..
      3- distinctUntilChanged
      屏蔽LiveData<X>的重复数据发射。
      即:LiveData<X>setValue被调用后,将会检测数据是否变更 ( 通过equals() ) ,未发生变更时,将会屏蔽本次更新。

    • ComputableLiveData
      一个未公开的类。(livedata-2.2.0)
      并非LiveData的子类,而是内部维护了一个LiveData
      该类内部LiveData的数据来源,并不来自数据的设置,而是来自子类实现的compute()方法的返回值。当数据更新时,调用invalidate()方法通知LiveData重新调用compute()计算数据。默认运行在一个大小为4,专用IO操作的线程池(arch_disk_io_%i)。


    LiveData的基本使用

    • 一般使用:
    class VM : ViewModel() {
        val dataSource = MutableLiveData<String>()
    }
    
    fun simple(vmOwner: ViewModelStoreOwner, lcOwner: LifecycleOwner) {
        val vm = ViewModelProvider(vmOwner).get(VM::class.java)
        vm.dataSource.observe(lcOwner, Observer { })
    }
    
    • 合并观察:
    class VM : ViewModel() {
        val intSource = MutableLiveData<Int>()
        val dataSource = MutableLiveData<String>()
    }
    
    fun simple(vmOwner: ViewModelStoreOwner, lcOwner: LifecycleOwner) {
        val vm = ViewModelProvider(vmOwner).get(VM::class.java)
        mediator.addSource(vm.intSource) { mediator.value = it.toString() }
        mediator.addSource(vm.dataSource) { mediator.value = it }
    }
    
    • 类型装换:
    fun simple() {
        val source: LiveData<Int> = MutableLiveData<Int>()
        val transfor: LiveData<String> = Transformations.map(source) {
            it.toString()
        }
    }
    
    • 数据源控制
    class VMCtrl : ViewModel() {
        private val stateSource = MutableLiveData<Int>()
        private val dataSource1 = MutableLiveData<String>()
        private val dataSource2 = MutableLiveData<String>()
        
        // stateSource 数据变更时会导致 outputSource 的数据源变更
        // 从而使 outputSource 数据发生变更
        val outputSource = Transformations.switchMap(stateSource) {
            if (it > 0) {
                dataSource1
            } else {
                dataSource2
            }
        }
    }
    
    • 重复事件屏蔽
    class VMUntilChanged : ViewModel() {
        private val source = MutableLiveData<Int>()
        // source 设置同一数值,无论多少次,outputSource 只会触发一次数据更新
        val outputSource = Transformations.distinctUntilChanged(stateSource)
    }
    

    LiveData的关键源码分析

    • LiveData的源码并不复杂,先从构造方法进行分析:

    在构造方法中就可以直接看到LiveData的两个关键成员
    1- mData:当前LiveData保存的数据。
    2- mVersion:当前mData的版本,默认-1,通过设置数据的构造方法实例化时,版本为0。

    static final Object NOT_SET = new Object();
    static final int START_VERSION = -1;
    
    public LiveData() {
        mData = NOT_SET;
        mVersion = START_VERSION;
    }
    
    public LiveData(T value) {
        mData = value;
        mVersion = START_VERSION + 1;
    }
    

    • LiveData.observe()作为入口分析:
    1. mObservers
      LiveData的观察者列表,可以看到实际对象是ObserverWrapper类型,即所有传入的observer都会被ObserverWrapper及其子类封装。
    2. assertMainThread()
      该处将会检测是否在主线程调用,否则抛出异常。
    3. LifecycleBoundObserver
      ObserverWrapper子类,观察者的生命周期管理在此处实现。
    4. existing.isAttachedTo(owner)
      观察者不允许绑定多个生命周期,否则抛出异常。
      同一个LiveData中,观察者不能同时 持有 / 忽略 生命周期特性,两者互斥。
    5. addObserver(wrapper)
      LifecycleBoundObserver加入对应生命周期回调以实现自动生命周期管理
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
    
    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);
    }
    

    • 在分析LifecycleBoundObserver前,先对其父类ObserverWrapper进行分析:
    1. mObserver
      在构造方法中传入的观察者实体,即用户构建的观察者。
    2. mActive
      当前观察者的激活状态,非激活状态时将不会触发观察者的回调。
    3. mLastVersion
      当前观察者对应的数据版本。
    4. shouldBeActive()
      判断观察者是否需要激活,由子类实现。
    5. isAttachedTo()
      判断观察者是否绑定了生命周期,由子类实现,默认为false
    6. detachObserver()
      观察者从LiveData移除时,LiveData会调用观察者包装对象的该方法,以处理必要的释放操作。
    7. 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;
            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);
            }
        }
    }
    
    • 其中第7activeStateChanged()在状态改变时,有如下性质:
    1. LiveData没有任何已激活的观察者,且此观察者激活,会回调LiveDataonActive()方法
    2. 此观察者取消激活后,LiveData没有任何已激活的观察者,会回调LiveDataonInactive()方法
    3. 观察者激活时,会通过dispatchingValue()通知LiveData尝试派发数据到观察者。

    • 关键方法dispatchingValue()

    该方法实际上LiveDatamObservers列表遍历进行通知尝试的方法。
    当指定观察者时,尝试对该观察者派发数据;当未指定具体的观察者时,将会遍历整个mObservers列表,对所有观察者派发数据。

    • dispatchingValue()的具体的流程:

    当前正在执行派发时,标记当次派发失效,在while循环处重新派发;
    指定派发目标时,只对该目标进行派发;
    未指定派发目标时,遍历mObservers,对所有观察者进行派发,派发期间检查失效标记,失效时,跳出当次遍历,在while循环处重新派发。

    1. mDispatchingValue:用于标记是否真正派发数据。
    2. mDispatchInvalidated:用于标记当前派发是否失效。
    3. considerNotify():观察者在该方法中根据条件判断是否进行派分数据。
    private boolean mDispatchingValue;
    private boolean mDispatchInvalidated;
    
    void dispatchingValue(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()

    该方法比较简单,主要是就是对观察者进行激活和版本校验。
    通过校验后,记录最新版本,并推送最新数据到观察者。

    1. !observer.mActive:当观察者未激活时,不执行派发。
    2. observer.shouldBeActive():重复检查观察者是否应该处于激活状态,检查失败则通知观察者取消激活。
    3. observer.mLastVersion >= mVersion:对比观察者版本,仅在版本低于LiveData版本时,通知观察者更新。
    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);
    }
    
    • 以上即可知道整个派发流程,即通过dispatchingValue()发起,considerNotify()校验,最终派发到观察者。

    • 回头分析LifecycleBoundObserver

    前文提到,LifecycleBoundObserverLiveData.observe()时,即绑定到观察者所指定的生命周期中,而绑定通过owner.getLifecycle().addObserver()传入自身作为对象,即LifecycleBoundObserver必然实现LifecycleObserver

    1. mOwner:在构造方法中要求传入生命周期对象。
    2. shouldBeActive():当处于生命周期处于Start - Stop之间时,观察者激活。
    3. onStateChanged():生命周期回调。
      非Destory状态,通过activeStateChanged(shouldBeActive())进行自我状态校验和处理。
      当处于Destory时,通知LiveData移除观察者,LiveData会把包装类从mObservers列表中移除,且触发其detachObserver()方法。
    4. isAttachedTo():直接判断生命周期对象是否相同。
    5. detachObserver():将自身从生命周期中移除,完成整个解绑过程。
    class LifecycleBoundObserver 
              extends ObserverWrapper 
              implements LifecycleEventObserver {
    
        final LifecycleOwner mOwner;
    
        LifecycleBoundObserver(LifecycleOwner owner, Observer observer) {
            super(observer);
            mOwner = owner;
        }
    
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle()
                            .getCurrentState()
                            .isAtLeast(STARTED);
        }
    
        @Override
        public void onStateChanged(LifecycleOwner source, 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,即LiveData.observe()加入的观察者,实现了生命周期侦测,完成激活状态管理和自动解绑操作。

    • 数据更新:

    数据更新有2个方法,且都比较简单,这里不贴出源码。

    1. setValue()
      只能在主线程执行,非主线程调用抛出异常。
      mVersion+1,mData设置为传入数据,并通过dispatchingValue(null)通知所有观察者数据数据更新。
      注意数据设置时,不会进行任何的对比和校验。即设置相同数据时,同样视为更新数据。·

    2. postValue()
      在任意线程中调用,传入的数据会暂存为mPendingData,最终会通过在主线程中调用setValue(mPendingData)进行数据更新。
      注意的是,postValue()被多次调用时,暂存数据mPendingData会被postValue()传入的数据覆盖,最终数据为最后一次的数据。而postValue()发起的主线程任务,在执行到前,只会存在一个任务。即:
      多次postValue()调用,在真正主线程执行前,共享同一次任务。而其中的暂存数据mPendingData会被覆盖为最后一次postValue()的传入值。
      使用postValue()应该注意该问题,极短时间内多次postValue()设置数据,会可能导致数据更新丢失。


    • LiveData.observeForever()

    添加忽略生命周期侦测特性的观察者。
    通过该方法加入的观察者不需要传入生命周期参数,即忽略生命周期侦测。
    所以使用该方法时需要注意,在合适的时候调用removeObserver()移除观察,避免发生内存泄漏。

    1. 通过observeForever()传入的观察者,将会被包装为AlwaysActiveObserver,该包装类的shouldBeActive()方法估计返回true,即任何数据更新都会通知到该观察者。
    2. 同一个LiveData中,观察者不能同时 持有 / 忽略 生命周期特性,两者互斥。
    3. 新加入的观察者,在方法的最后都会通过activeStateChanged(true)通知LiveData更新数据到观察者。
    public void observeForever(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);
    }
    

    • 观察者移除:

    观察者移除有2个方法,且都比较简单,这里不贴出源码。

    1. removeObserver(Observer observer)
      该方法用于移除指定的观察者,如果绑定生命周期,则会解除绑定。
    2. removeObservers(LifecycleOwner owner)
      仅针对通过LiveData.observe()添加,绑定了生命周期的观察者,移除维护中的所有生命周期对象为传入对象的观察者。最终也是通过removeObserver()逐一移除。

    相关文章

      网友评论

          本文标题:深入理解AAC架构 - LiveData 使用以及整体机制源码

          本文链接:https://www.haomeiwen.com/subject/pnzcqhtx.html