深入AAC架构,彻底理解LiveData的用法

/   今日科技快讯   /

近日,根据纽约时报实时疫情地图,美国共有28个州报告了确诊病例。其中华盛顿州、加州疫情最为严重,因此诸如微软、苹果等西海岸科技巨头也备受冲击。苹果公司建议总部所有1.2万名员工在家办公。

/   作者简介   /

本篇文章来自七零八落问号的投稿,分享了LiveData的使用以及相关的源码分析,是之前《深入AAC架构,彻底理解ViewModel的用法》这篇文章的姊妹篇,相信会对大家有所帮助!同时也感谢作者贡献的精彩文章。

七零八落问号的博客地址:

https://www.jianshu.com/p/4a65ee05e6a1

/   LiveData的主要工作   /

一个带有生命周期侦测特性的数据持有者。


AAC架构中的实际数据持有者,通常存放在ViewModel中,通过ViewModel脱离生命周期对数据的影响。


本身机制是观察者模式,在数据更新时,会通知所有已激活 (或根据需求通知未激活) 的观察者最新数据。


由于生命周期侦测的特性,LiveData在添加观察者时,要求观察者附带其生命周期所在的LifecycleOwner。

官方链接:

https://developer.android.google.cn/topic/libraries/architecture/livedata

/   LiveData的主要类   /

LiveData

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

MutableLiveData

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

Observer


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

LiveData$ObserverWrapper


LiveData的内部类,观察者实例的容器类的抽象父类。注册到LiveData的观察者,被会ObserverWrapper的子类包装,再加入观察者列表。


维护了对应观察者的:

  1. 当前数据版本

  2. 当前观察者的激活状态

同时负责通知LiveData的onActive()和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)

map

使LiveData通过Function转换为LiveData。即:LiveData数据更新 - > Function转换 -> MediatorLiveData数据更新


switchMap

根据LiveData的数据,根据Function返回需要观察的LiveData。即:LiveData数据更新 - > Function选择数据源 -> MediatorLiveData的数据源更新。

和map对比,map的数据源直接来自LiveData;而switchMap的数据源是Function返回的LiveData,LiveData对于switchMap来说只是个数据源控制器。

distinctUntilChanged

屏蔽LiveData的重复数据发射。即:LiveData的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()
}

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()
    val dataSource = MutableLiveData()
}

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 = MutableLiveData()
    val transfor: LiveData = Transformations.map(source) {
        it.toString()
    }
}

数据源控制:

class VMCtrl : ViewModel() {
    private val stateSource = MutableLiveData()
    private val dataSource1 = MutableLiveData()
    private val dataSource2 = MutableLiveData()

    // stateSource 数据变更时会导致 outputSource 的数据源变更
    // 从而使 outputSource 数据发生变更
    val outputSource = Transformations.switchMap(stateSource) {
        if (it > 0) {
            dataSource1
        } else {
            dataSource2
        }
    }
}

重复事件屏蔽:

class VMUntilChanged : ViewModel() {
    private val source = MutableLiveData()
    // source 设置同一数值,无论多少次,outputSource 只会触发一次数据更新
    val outputSource = Transformations.distinctUntilChanged(stateSource)
}

单次事件发射

https://github.com/android/architecture-samples/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/SingleLiveEvent.java

事件总线

https://www.jianshu.com/p/300ab972df6c

/   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()作为入口分析:

mObservers

LiveData的观察者列表,可以看到实际对象是ObserverWrapper类型,即所有传入的observer都会被ObserverWrapper及其子类封装。

assertMainThread()

该处将会检测是否在主线程调用,否则抛出异常。

LifecycleBoundObserver

ObserverWrapper子类,观察者的生命周期管理在此处实现。

existing.isAttachedTo(owner)

观察者不允许绑定多个生命周期,否则抛出异常。

同一个LiveData中,观察者不能同时 持有 / 忽略 生命周期特性,两者互斥。

addObserver(wrapper)

将LifecycleBoundObserver加入对应生命周期回调以实现自动生命周期管理。

private SafeIterableMap, ObserverWrapper> mObservers = new SafeIterableMap<>();

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer 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进行分析:

mObserver

在构造方法中传入的观察者实体,即用户构建的观察者。

mActive

当前观察者的激活状态,非激活状态时将不会触发观察者的回调。

mLastVersion

当前观察者对应的数据版本。

shouldBeActive()

判断观察者是否需要激活,由子类实现。

isAttachedTo()

判断观察者是否绑定了生命周期,由子类实现,默认为false。

detachObserver()

观察者从LiveData移除时,LiveData会调用观察者包装对象的该方法,以处理必要的释放操作。

activeStateChanged()

观察者的激活状态通过该方法作出改变。

private abstract class ObserverWrapper {
    final Observer mObserver;
    boolean mActive;
    int mLastVersion = START_VERSION;

    ObserverWrapper(Observer 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);
        }
    }
}

其中activeStateChanged()在状态改变时,有如下性质:

  1. LiveData没有任何已激活的观察者,且此观察者激活,会回调LiveData的onActive()方法。

  2. 此观察者取消激活后,LiveData没有任何已激活的观察者,会回调LiveData的onInactive()方法。

  3. 观察者激活时,会通过dispatchingValue()通知LiveData尝试派发数据到观察者。

关键方法dispatchingValue()。该方法实际上LiveData对mObservers列表遍历进行通知尝试的方法。

当指定观察者时,尝试对该观察者派发数据;当未指定具体的观察者时,将会遍历整个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, 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。

前文提到,LifecycleBoundObserver在LiveData.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个方法,且都比较简单,这里不贴出源码。

setValue()

只能在主线程执行,非主线程调用抛出异常。mVersion+1,mData设置为传入数据,并通过dispatchingValue(null)通知所有观察者数据数据更新。

注意数据设置时,不会进行任何的对比和校验。即设置相同数据时,同样视为更新数据。

postValue()

在任意线程中调用,传入的数据会暂存为mPendingData,最终会通过在主线程中调用setValue(mPendingData)进行数据更新。

注意的是,postValue()被多次调用时,暂存数据mPendingData会被postValue()传入的数据覆盖,最终数据为最后一次的数据。而postValue()发起的主线程任务,在执行到前,只会存在一个任务。多次postValue()调用,在真正主线程执行前,共享同一次任务。而其中的暂存数据mPendingData会被覆盖为最后一次postValue()的传入值。

使用postValue()应该注意该问题,极短时间内多次postValue()设置数据,会可能导致数据更新丢失。

LiveData.observeForever()

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

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

public void observeForever(Observer 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个方法,且都比较简单,这里不贴出源码。

removeObserver(Observer observer)

该方法用于移除指定的观察者,如果绑定生命周期,则会解除绑定。

removeObservers(LifecycleOwner owner)

仅针对通过LiveData.observe()添加,绑定了生命周期的观察者,移除维护中的所有生命周期对象为传入对象的观察者。最终也是通过removeObserver()逐一移除。

推荐阅读:

奇妙的Window之旅

Handler的文章一大把,这篇写的真形象

写一篇最好懂的https讲解

欢迎关注我的公众号

学习技术或投稿

长按上图,识别图中二维码即可关注

你可能感兴趣的:(深入AAC架构,彻底理解LiveData的用法)