Jetpack框架探究02:LiveData组件的使用与源码分析

总目录

Jetpack框架探究01:Lifecycle组件的使用与源码分析
Jetpack框架探究02:LiveData组件的使用与源码分析
Jetpack框架探究03:ViewModel组件的使用与源码分析
Jetpack框架探究04:Room组件的使用与源码分析
Jetpack框架探究05:WorkerManager组件的使用与源码分析

1. LiveData简介

1.1 LiveData基本使用

 LiveData是JetPack提供的基于观察者的消息订阅/分发组件,是一种可观察的数据存储器类,同时它又基于JetPack的Lifecycle组件,因此具有宿主(如Activity、Fragment)生命周期感知能力,这种感知能力可确保LiveData仅分发消息给处于活跃状态的观察,所谓活跃状态是指观察者所在宿主的生命周期处于STARTREDRESUMED状态。此外,当宿主的生命状态变为DESTORYED时,LiveData会自动将在该宿主注册的所有观察者移除。LiveData组件优势如下:

  • 能够感知观察者所在宿主生命周期,并适当时机分发数据;

  • 宿主销毁时自动移除观察者,防止内存泄漏、NEP等异常;

  • 数据始终保持最新状态;

  • 支持黏性事件的分发;

  • 共享资源;

1.1 LiveData基本使用

 LiveData的使用非常简单,主要分为以下两步:

(1)添加依赖,直接导入androidx库即可;

dependencies {
    implementation 'androidx.appcompat:appcompat:1.2.0'
}

(2)创建、使用LiveData对象;

LiveData是一个抽象类,通常使用MutableLiveData来创建一个LiveData对象,MutableLiveData是LiveData的子类,它只包含setValue()postValue()两个方法用于更新LiveData的value字段值,即会触发将value分发给注册的观察者。

// a.创建一个MutableLiveData对象
val testLiveData = MutableLiveData<String>()
// b.使用LiveData对象注册一个观察者
testLiveData.observe(this, Observer {
    Toast.makeText(this, "message-->$it", Toast.LENGTH_SHORT).show()
})
// c.使用LiveData对象发生消息事件
// 如果是在主线程发射事件,使用setVaule()
// 如果是在异步线程发射事件,使用postValue()
testLiveData.value = "Hello LiveData"

 除此之外,我们还可以使用MediatorLiveData类将多个LiveData绑定在一起,便于统一观察多个LiveData发射的数据进行统一处理,同时也可以作为一个LiveData,被其他Observer观察。实际上,MediatorLiveData类继承于MutableLiveData,因此,它也是一个LiveData。使用方法如下:

// a. 创建两个LiveData和一个Observer
val liveData1 = MutableLiveData<String>()
val liveData2 = MutableLiveData<String>()
val observer = Observer<String> {
    Toast.makeText(this, "message2-->$it", Toast.LENGTH_SHORT).show()
}
// b. 将两个LiveData绑定在一起
// 统一使用一个Observer
val mediatorLiveData = MediatorLiveData<String>()
mediatorLiveData.addSource(liveData1, observer)
mediatorLiveData.addSource(liveData2, observer)

 至此上述案例中,无论liveData1还是liveData2发送了新数据,observer便能观察得到。另外,LiveData框架还提供了一个Transformations.map操作符,允许我们对LiveData的数据进行变换,并返回一个新的LiveData对象,这点类似于RxJava的flapMap操作符。使用方法如下:

val loginLiveData = MutableLiveData<Boolean>()
val newLiveData = Transformations.map(loginLiveData) { isSuccess ->
    if (isSuccess) {
        "Login success!"
    } else {
        "Login failed!"
    }
}
newLiveData.observe(this, Observer {
    Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
})

/**发送事件
 *
 * 延迟3秒,模拟网络登录成功
 */
Thread(Runnable {
    try {
        Thread.sleep(3000)
    } catch (e: Exception) {
        e.printStackTrace()
    }
    loginLiveData.postValue(true)
}).start()

 嗯。不出意外的话,最终会打印"Login success!"。需要注意的是,LiveData还支持与Room协程一起使用,这两个知识点我将在接下来的文章中详细分析。接下来,我们来看一个实战案例小牛试一把刀。

1.2 LiveData实战案例

 为了加深对LiveData的理解,这里举一个开发中常用的案例–事件总线,所谓事件总线,是指一种基于发布-订阅机制实现的集中式事件处理机制,它允许不同的组件之间进行彼此通信而又不需要相互依赖,从而达到一种解耦的目的。在日常开发中常用的事件总线框架有EventBus、RxBus等,其中EventBus原理如下图所示:

image

 这类事件总线使用非常简单,但在使用的过程中要注意及时取消订阅,否则可能会导致内存泄漏。另外,由于这类框架无法感知组件的生命周期,当组件处于不活跃状态时,仍然会向组件中的观察者分发事件,这就可能导致资源的浪费,甚至出现NPE异常奔溃。基于此,我们可以利用LiveData框架实现具有同等效果的事件总线,由于LiveData基于Lifecycle实现,因此它可以感知组件的生命周期,所以只有在组件处于活跃状态时才会分发事件,并且在组件被销毁之前自动移除注册的所有观察者。

/**
 * author: jiangdg
 * date: 2021/1/16 11:40 AM
 * description: 使用LiveData实现事件总线,单例模式
 */
object EventDataBus {

    private val mLiveDataMap = ConcurrentHashMap<String, LiveData<*>>()

    /** 注册事件总线
     *
     * key 表示事件总线名称
     * T 表示事件类型,泛型
     */
    fun <T> with(key: String): MutableLiveData<T> {
        var liveData = mLiveDataMap[key] as? MutableLiveData<T>
        if (liveData == null) {
            liveData = MutableLiveData<T>().apply {
                mLiveDataMap[key] = this
            }
        }
        return liveData 
    }
}

 从EventDataBus的源码可知,使用LiveData实现一个事件总线框架非常简单,就是定义一个泛型方法with()和一个线程安全的ConcurrentHashMap,其中,with()方法接收一个String类型的参数,表示某个事件总线的名称,同时返回一个LiveData用于注册观察者和发送某个类型的事件(实际就是更新LiveData的value) ;而Map就用来存储某个事件总线及其对应的LiveData。

 接下来,在Activity或Fragment等组件中,获取指定名称事件总线对应的LiveData,调用它的observer()方法注册一个观察者。代码如下:

private const val BUS_KEY = "LoginStatus"

EventDataBus.with<LoginStatus>(BUS_KEY).observe(this, Observer {
    Log.i("LoginStatus", "I am observer1, status = ${it.msg}")
})

 然后,再获取与注册观察者相同的LiveData,调用它的setValue()postValue()方法更新其值,即完成事件消息的发送。代码如下:

// 任何线程发送消息
EventDataBus.with<LoginStatus>(BUS_KEY).postValue(LoginStatus(0, "login success"))

// 仅主线程发送消息
EventDataBus.with<LoginStatus>(BUS_KEY).setValue(LoginStatus(0, "login success"))

 最后,打印Log日志为:

LoginStatus: send login status...
LoginStatus: I am observer1, status = login success
LoginStatus: I am observer2, status = login success

 上述案例描述了在子线程模拟用户登录操作,当获得操作结果后向事件总线发送登录状态事件,而注册了事件监听的地方将会收到登录状态事件。但是,当我们重新创建一个Activity,并注册新的观察者和重新发送一条登录事件时,新注册的观察者不仅收到了新的事件消息,之前我们发送的事件也收到了。

LoginStatus: I am observer3 status = login success
LoginStatus: send login status again...
LoginStatus: I am observer3 status = login failed, account not exist

 通常来说,这并不是我们想要的,因为这有可能导致我们的数据处理出错,而我们只需要能够实时收到事件就可以了。之所以出现这种情况,这跟LiveData的实现机制有关系,接下来我们就通过分析其源码并找到其中的原因,然后改进我们的事件总线。

2. LiveData实现原理

2.1 LiveData组件框架

 LiveData组件框架类图:

在这里插入图片描述

 上图中的类或接口具体说明如下:

  • LiveData

 LiveData是一个可观察的数据持有类,它能够感知ActivityFragmentService等组件(宿主)的生命周期,并确保只有在观察者所在宿主的生命周期处于活跃状态(RESUMED或STARTED)时,才会通知这些这些观察者更新数据。此外,当宿主被销毁时LiveData会自动移除在该宿主中注册的所有观察者,从而防止内存泄漏。LiveData部分源码如下:

public abstract class LiveData<T> {
    // Observer集合
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers
                    = new SafeIterableMap<>();    
    // 数据版本
    // 每发射一个数据mData,该字段+1
    private int mVersion = START_VERSION;
    
    // LiveData存储的数据
    private volatile Object mData = NOT_SET;
 
    // 注册一个观察者
    // 仅限于在主线程调用
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    }
    
    // 注册一个观察者
    // 仅限于主线程调用,当宿主销毁时,LiveData不会将此观察者移除
    @MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
    }
    
    // 更新数据
    // 允许在任何线程中发射数据
    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);
    }

    // 空方法
    // 当注册的观察者数目不为0时被调用(0-->1)
    protected void onActive() {

    }

    // 空方法
    // 当注册的观察者数目变为0时被调用(1-->0)
    protected void onInactive() {

    }
    ...
}

 从LiveData的源码可知,它主要维护了mObserversmVersionmData三个属性,其中,mObservers属性为注册监听LiveData的观察者集合;mVersion属性为LiveData存储数据的版本号,默认为0,每次更新LiveData的数据该字段加1,同时该字段也是决定是否向某个观察者发射数据的关键;mData属性即为LiveData存储的数据,支持任意类型的数据存储。

  • MutableLiveData

 MutableLiveData是LiveData的子类,由于LiveData是一个抽象类,因此在实例化一个LiveData对象时就需要通过它来实现。它向外暴露的postValue()setValue()方法将用于更新LiveData的数据,或者可以理解为向所有的观察者发射数据,其中,postValue()可以在任意线程中发射数据,而setValue()仅限于主线程中发射数据。MutableLiveData源码如下:

@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {

    // 允许在任何线程中发射数据
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    // 仅限于在主线程中发射数据
    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}
  • Observer

 Observer是一个回调接口,在LiveData框架中充当观察者的角色。当LiveData的数据更新时,该接口的onChanged()方法被回调。Observer接口源码如下:

public interface Observer<T> {
    /**
     * 当LiveData的数据更新时,该方法被回调
     *
     * @param t  新数据,T为泛型类型
     */
    void onChanged(T t);
}
  • ObserverWrapper

 ObserverWrapper是LiveData的内部类,它主要用于对观察者Observer作进一步封装,同时记录观察者的活跃状态mActive以及数据的版本号mLastVersion。其中,mActive决定了LiveData只有在当前Observer所在宿主处于活跃状态时才分发数据给它;而mLastVersion将与LiveData的mVersion字段共同决定是否分发数据给观察者。ObserverWrapper源码如下:

private abstract class ObserverWrapper {
    // 观察者
    final Observer<? super T> mObserver;
    // 观察者活跃状态
    boolean mActive;
    // 观察者版本号,默认=START_VERSION=-1
    int mLastVersion = START_VERSION;

    ObserverWrapper(Observer<? super T> observer) {
        mObserver = observer;
    }
    
    abstract boolean shouldBeActive();

    boolean isAttachedTo(LifecycleOwner owner) {
        return false;
    }

    void detachObserver() {
    }

    // 更新观察者的活跃状态
    // 并且根据当前LiveData的观察者数量决定是否
    // 回调LiveData的onActive()和onInactive()方法
    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);
        }
    }
}
  • LifecycleBoundObserver

 从ObserverWrapper的源码可知,它虽然提供了判断当前Obsever的活跃状态、反注册等方法,但是这些方法均是抽象的,ObserverWrapper本身就是一个抽象类。既然是抽象类,那么必定就会有具体的实现类来完成这些操作,而这个实现类就是LifecycleBoundObserver,它持有观察者所在的宿主LifecycleOwner,并继承于LifecycleEventObserver,因此它能够准确的知道宿主的生命周期变化,因为当我们将Observer注册到LiveData时,LifecycleBoundObserver就会被注册到宿主的Lifecycle中,这点从LiveData的observer()方法最后一行得知。LifecycleBoundObserver源码如下:

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
    // 观察者宿主
    @NonNull
    final LifecycleOwner mOwner;

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

    // 宿主的生命周期状态至少为STARTED时才算是活跃状态
    // 即STARTED和RESUMED状态
    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    // 当宿主生命周期变化时,该方法被回调
    // 如果宿主生命周期处于DESTROYED状态,将Observer从LiveData中移除
    // 否则,更新Observer的活跃状态
    @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;
    }

    // 将当前LifecycleBoundObserver从Lifecycle中移除
    // 这部操作是在将Observer从LiveData中移除时执行
    @Override
    void detachObserver() {
        mOwner.getLifecycle().removeObserver(this);
    }
}
  • AlwaysActiveObserver

 AlwaysActiveObserver也是ObserverWrapper的实现类,与LifecycleBoundObserver不同的时,它用于LiveData的observeForever()方法中,用于向LiveData注册一个永远处于活跃状态的观察者。换句话说,无论被注册观察者所在宿主是否存在,这个观察者总是能给监听到LiveData的数据变化,除非我们调用LiveData的removeObserver()方法将其移除(反注册)。AlwaysActiveObserver源码如下:

private class AlwaysActiveObserver extends ObserverWrapper {

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

    // 当前Observer永远处于活跃状态
    @Override
    boolean shouldBeActive() {
        return true;
    }
}

2.2 LiveData实现原理

2.2.1 观察者注册过程

 LiveData提供了两种方式用于注册一个观察者,即observe()observeForver()方法,其中,前者注册的观察者只有其所属宿主处于活跃状态时才能接收到LiveData发射的数据,并且当宿主销毁时LiveData会自动对相关的观察者进行移除,从而防止出现内存泄漏等问题;后者注册的观察者没有生命周期的概念,即无论何时都能够收到LiveData发射的最新数据,因此在使用完毕时需要我们手动移除。首先,我们先看下observer()的注册过程:

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    // 宿主生命周期处于DESTROYED状态
    // 注册失败
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    // 将观察者observer包装成LifecycleBoundObserver
    // 并将其存储到mObservers集合中且已经绑定Owner,如果集合中已经存在
    // 则说明反复注册,抛出异常
    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.observer()方法源码可知,它首先会判断当前观察者是否在宿主的生命周期为DESTROYED时注册,即在onDestory()方法中注册,就没有必要再继续处理了;然后将观察者observer包装成LifecycleBoundObserver,并将其存储到mObservers集合中,如果集合中已经存在,说明之前已经注册过,则抛出异常;最后,将包装好的LifecycleBoundObserver对象注册到宿主的Lifecycle中,用于监听宿主的生命周期变化,这也是LiveData能够感知观察者宿主生命周期状态的关键所在。

注:LifecycleBoundObserver实现了LifecycleEventObserver。

 接下来,我们看下observeForver()的注册过程:

@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
    assertMainThread("observeForever");
    // 判断是否已经注册,并完成注册
    AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    // 将Observer的状态永远设置为活跃状态
    wrapper.activeStateChanged(true);
}

 从上述源码可知,该方法的实现与observe差不多,它首先会将observer包装成AlwaysActiveObserver,并将其存储到mObservers集合中,同时判断是否是已经注册过,如果是就抛出异常;然后,将observer的状态标记为活跃状态,这就意味着,只要没有将该observer从LiveData移除,它将永远能够收到LiveData发射的数据。removeObserver()源码如下:

@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
    assertMainThread("removeObserver");
    // 1. 将observer从集合中移除
    ObserverWrapper removed = mObservers.remove(observer);
    if (removed == null) {
        return;
    }
    // 2. 取消对宿主生命周期的监听
    // mOwner.getLifecycle().removeObserver(this);
    removed.detachObserver();
    
    // 3. 将observer的状态设定为非活跃状态
    removed.activeStateChanged(false);
}

注:无论哪种方式注册或者移除观察者,只能在主线程中完成。

需要特别注意的是,无论是observer()还是observeForever(),当新注册一个观察者到LiveData时,它们均会去调用ObserverWrapperactiveStateChanged()方法,并将观察者的状态mActive置为true。通过查看该方法源码可知,它会去调用dispatchingValue()方法尝试第一次数据分发,最终该方法将直接调用considerNotify()方法。由于是新注册的observer,它的数据版本号必定小于等于LiveData的数据版本号,就可能导致新注册的observer收到LiveData的旧数据,这就是我们在实战案例中遇到的问题原因所在。 相关源码如下:

 void activeStateChanged(boolean newActive) {
        // newActive = true
        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);
        }
    }
    
  private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    // 如果LiveData的mData有值
    // 新注册的Observer数据版本号必定小于LiveData的数据版本号
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    // 将Observer的数据版本号与LiveData的对齐
    // 并将LiveData的当前存储的数据mData(旧数据)分发给当前Observer
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

2.2.2 数据更新过程

 LiveData提供了两种方式用于向所有观察者发射任意类型的数据,即setValue()postValue()方法,其中,前者仅限在主线程中更新LiveData的中的数据,后者允许再任意线程中更新LiveData中的数据。实质上,通过查看postValue()的源码发现,它还是通过Handler消息处理机制切换到主线程调用setValue()方法完成数据更新。相关源码如下:

volatile Object mPendingData = NOT_SET;

protected void postValue(T value) {
    boolean postTask;
    // 同步处理
    // 将数据保存到缓存变量mPendingData
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    // 通过Handler消息处理机制切换到主线程
    // 即获取主线程的Handler,调用mMainHandler.post(runnable)实现
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

private final Runnable mPostValueRunnable = new Runnable() {
    @Override
    public void run() {
        // 同步处理
        // 读取缓存变量mPendingData到newValue
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        // 调用setValue更新LiveData的mData值
        setValue((T) newValue);
    }
};

 接下来,我们就看下setValue()是如何更新LiveData的数据,并将其通知给对应的观察者。

static final int START_VERSION = -1;
private int mVersion = START_VERSION;

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    // LiveData数据版本号+1
    mVersion++;
    // 更新LiveData的mData属性
    mData = value;
    // 进入数据分发流程
    dispatchingValue(null);
}

 从setValue()方法源码可知,它首先将LiveData的mVersion属性自增1,这个属性表示LiveData存储的数据mData版本号,默认值为-1,每一次更新mData的值该属性自增1;然后,将最新数据赋值给mData;最后,调用dispatchingValue()方法进入数据分发流程。dispatchingValue()源码如下:

private boolean mDispatchingValue;

void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        // 注意:新注册的观察者,调用dispatchingValue时
        // initiator不为空
        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) {
    // 1. 当前observer状态mActive为false
    // 则直接不分发数据给它
    if (!observer.mActive) {
        return;
    }
    // 2. 判断当前observer的宿主是否活跃状态
    // 如果不处于活跃状态,调用activeStateChanged()更新observer的状态mActive为false
    // 并决定是否回调LiveData的onInactive方法(LiveData的观察者数目==0)
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    // 3. 如果observer的数据版本>=LiveData的数据版本
    // 说明已经分发过了或出现异常,则不继续分发
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    // 4. 调用observer的onChanged方法向其分发数据
    // 并将observer的数据版本与LiveData的版本对齐
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

3. LiveData实战案例(改进版)

 通过对LiveData源码深度分析,我们知道导致1.2小节事件总线案例新注册的观察者会收到LiveData旧数据的原因在于,LiveData源码中主要是通过对比自身的数据版本号mVersion和观察者的数据版本号mLastVersion来决定是否分发数据给观察者,这就造成了当新注册一个观察者时mLastVersion决定是小于mVersion,从而触发了LiveData数据分发逻辑,将当前存储的旧数据分发给当前观察者,而这种情况也被称为黏性事件。为了不产生黏性事件效果,我们只要保证当新注册一个观察者时,在LiveData判断数据版本号之前,将观察者的数据版本号初始化与LiveData的对齐。

 EventDataBus类改进如下:

/**
 * author: jiangdg
 * date: 2021/1/16 11:40 AM
 * description: 使用LiveData实现,单例模式
 */
object EventDataBus {

    private val mLiveDataMap = ConcurrentHashMap<String, LiveData<*>>()

    /** 注册事件总线
     *
     * key 表示事件总线名称
     * T 表示事件类型,泛型
     */
    fun <T> with(key: String): BusLiveData<T> {
        var liveData = mLiveDataMap[key] as? BusLiveData<T>
        if (liveData == null) {
            liveData = BusLiveData<T>(key).apply {
                mLiveDataMap[key] = this
            }
        }
        return liveData
    }

    /** 自定义LiveData
     *
     * 通过自己管理LiveData的version,便于后续同步Observer的version字段
     */
    class BusLiveData<T>(private val busName: String): MutableLiveData<T>() {
        internal var mVersion = 0

        fun sendMessage(message: T) {
            ++mVersion
            value = message
        }

        fun postMessage(message: T) {
            ++mVersion
            postValue(message)
        }

        override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
            // 监听宿主发生销毁事件,检查LiveData是否还有其他观察者
            // 如果没有主动把LiveData移除掉
            owner.lifecycle.addObserver(object : LifecycleEventObserver {
                override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                    if (event == Lifecycle.Event.ON_DESTROY) {
                        if (mLiveDataMap[busName]?.hasObservers() == false) {
                            mLiveDataMap.remove(busName)
                        }
                    }
                }
            })
            // 重新对observer包装
            // 使用代理observer,它会仅把最新事件分发给观察者
            super.observe(owner, ProxyObserver(this, observer))
        }
    }

    /** 代理Observer
     *
     *  通过自己管理Observer的version字段,控制是否分发事件
     */
    internal class ProxyObserver<T>(
        private val liveData: BusLiveData<T>,
        private val observer: Observer<in T>
    ): Observer<T> {
        // 初始化Observer的version与LiveData的一致
        private var mLastVersion = liveData.mVersion

        // 只有在LiveData有最新数据时,才调用Observer的onChanged分发事件
        // 其中,判断有新数据的条件时:LiveData.version > Observer.version
        override fun onChanged(data: T) {
            if (mLastVersion >= liveData.mVersion) {
                return
            }
            mLastVersion = liveData.mVersion
            observer.onChanged(data)
        }
    }
}

 从EventDataBus源码可知,这里采样了自己维护一套version + 代理的方式来改进,具体来说就是我们自己管理LiveData和Observer的数据版本号,且对Observer进行了包装(代理)。当新注册一个Observer时,就让Observer的mLastVersion等于LiveData的mVersion;当LiveData向代理ProxyObserver分发数据时,它的onChanged方法会被回调,这时再判断是否满足分发条件,如果满足(是最新数据),再分发给真正Observer。

 最终打印结果:

LoginStatus: send login status...
LoginStatus: I am observer1, status = login success
LoginStatus: I am observer2, status = login success
LoginStatus: send login status again...
LoginStatus: I am observer3 status = login failed, account not exist

4. 参考文献

1. LiveData概述


Github源码:ExampleJetpack

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 黑客帝国 设计师:白松林 返回首页