Jetpack之LiveData

Jetpack之LiveData

1. 介绍

LiveData 具有生命周期感知能力,学习LiveData之前最好了解一下Lifecycle的知识,以下是来自官网的介绍:

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。 如果观察者(由 Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。

使用 LiveData 具有以下优势:

  1. 确保界面符合数据状态 LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知 Observer 对象。您可以整合代码以在这些 Observer 对象中更新界面。这样一来,您无需在每次应用数据发生变化时更新界面,因为观察者会替您完成更新。

  2. 不会发生内存泄漏 观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。

  3. 不会因 Activity 停止而导致崩溃 如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。

  4. 不再需要手动处理生命周期 界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。

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

  6. 适当的配置更改 如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。

  7. 共享资源 您可以使用单例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象。

2. 使用

使用LiveData分为创建、监听(观察)、通知(更新)三个步骤:

  1. 创建 LiveData 对象 LiveData 是一种可用于任何数据的封装容器,其中包括可实现 Collections 的对象,如 List。LiveData 对象通常存储在 ViewModel 对象中,并可通过 getter 方法进行访问,如以下示例中所示:
class NameViewModel : ViewModel() {
    // 创建一个String类型的LiveData
    val currentName: MutableLiveData by lazy {
        MutableLiveData()
    }
}

最初,LiveData 对象中的数据并未经过设置。

注意:请确保用于更新界面的 LiveData 对象存储在 ViewModel 对象中,而不是将其存储在 Activity 或 Fragment 中,原因如下:

  • 避免 Activity 和 Fragment 过于庞大。现在,这些界面控制器负责显示数据,但不负责存储数据状态。
  • 将 LiveData 实例与特定的 Activity 或 Fragment 实例分离开,并使 LiveData 对象在配置更改后继续存在。
  1. 观察 LiveData 对象 在大多数情况下,应用组件的 onCreate() 方法是开始观察 LiveData 对象的正确着手点,原因如下:
  • 确保系统不会从 Activity 或 Fragment 的 onResume() 方法进行冗余调用。
  • 确保 Activity 或 Fragment 变为活跃状态后具有可以立即显示的数据。一旦应用组件处于 STARTED 状态,就会从它正在观察的 LiveData 对象接收最新值。只有在设置了要观察的 LiveData 对象时,才会发生这种情况。

通常,LiveData 仅在数据发生更改时才发送更新,并且仅发送给活跃观察者。此行为的一种例外情况是,观察者从非活跃状态更改为活跃状态时也会收到更新。此外,如果观察者第二次从非活跃状态更改为活跃状态,则只有在自上次变为活跃状态以来值发生了更改时,它才会收到更新。 以下示例代码说明了如何开始观察 LiveData 对象:

class NameActivity : AppCompatActivity() {

    // 'by viewModels()'是 activity-ktx 组件,使用 ViewModelProvider 初始化NameViewModel也可以
    private val model: NameViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 省略其他代码...
        // 创建更新UI的观察者
        val nameObserver = Observer { newName ->
            // 更新UI,这里是TextView的文本内容
            nameTextView.text = newName
        }
        // 观察LiveData,将this作为LifecycleOwner和观察者传入。 
        model.currentName.observe(this, nameObserver)
    }
}

在传递 nameObserver 参数的情况下调用 observe()后,系统会立即调用onChanged(),从而提供 mCurrentName 中存储的最新值。如果 LiveData 对象尚未在 mCurrentName 中设置值,则不会调用 onChanged()

这句话的意思是, nameObserver 先改变再监听(观察),依旧可以观察到改变后的数据,即LiveData是有粘性的。

  1. 更新 LiveData 对象 LiveData 没有公开可用的方法来更新存储的数据。MutableLiveData 类将公开 setValue(T)postValue(T) 方法,如果您需要修改存储在 LiveData对象中的值,则必须使用这些方法。通常情况下会在ViewModel中使用 MutableLiveData,然后 ViewModel 只会向观察者公开不可变的 LiveData 对象。

设置观察者关系后,您可以更新LiveData 对象的值(如以下示例中所示),这样当用户点按某个按钮时会触发所有观察者:

button.setOnClickListener {
    val anotherName = "John Doe"
    model.currentName.setValue(anotherName)
}

在本示例中调用 setValue(T) 导致观察者使用值John Doe 调用其 onChanged() 方法。本示例中演示的是按下按钮的方法,但也可以出于各种各样的原因调用 setValue()postValue() 来更新 mName,这些原因包括响应网络请求或数据库加载完成。在所有情况下,调用 setValue()postValue() 都会触发观察者并更新界面。

注意:您必须调用 setValue(T) 方法以从主线程更新 LiveData 对象。如果在工作器线程中执行代码,您可以改用 postValue(T) 方法来更新 LiveData 对象。

3. 分析

基于androidx.lifecycle:lifecycle-livedata-core:2.3.1

根据前面的介绍,思考几个问题:

  1. LiveData如何做到仅更新处于活跃生命周期状态的应用组件观察者?

  2. LiveData粘性效果是怎么实现的?能否去掉?如何去掉粘性效果?

  3. LiveData中的setValue(T)和postValue(T)有什么区别?内部分别怎么实现的?

3.1 LiveData的相关类和结构

首先看一下源码包,基于androidx.lifecycle:lifecycle-livedata-core:2.3.1

livedata-package.png

可以看到源码包中的类出奇的少,但是其内部用到了Lifecycle的相关类,看一下类图:

LiveData.png

LiveData本身是一个很简单的观察者模式,通过observe(LifecycleOwner owner, @Observer observer)方法向其成员变量SafeIterableMap, ObserverWrapper> mObservers添加观察者,在数据发生改变时调用setValut(T)postValue(T)来通知观察者发生数据改变。

那么LiveData如何做到仅更新处于活跃生命周期状态的应用组件观察者,原理也比较简单,维护一个成员变量boolean mActive,在通知观察者之前判断该变量为true时则通知,否则不通知。而boolean mActive表示了观察者当前是否为活跃状态,这个状态的改变则依赖于Lifecycle生命周期组件。

  • Observer

Observer只有一个方法的观察者,LiveData发生变化时通知的就是它。

  • LiveData

关键类,所有关键源码也基本上在这个类里,后面分析源码时详细讲解:

  • 内部维护了观察者列表、提供了添加观察者的方法、数据更新方法(通知观察者);

  • 一个内部抽象类ObserverWrapper,关键变量boolean mActive由它维护;

  • 两个内部类LifecycleBoundObserverAlwaysActiveObserver,类图中有说明区别;

  • MutableLiveData

由于LiveData中的 setValue(T)postValue(T)protected,外部无法访问,那么该怎么更新内容呢?Android提供了MutableLiveData,该类目前也只有一个作用,即将 setValue(T)postValue(T) 方法公开public

LifecycleObserverLifecycleEventObserverLifecycle的知识,这里不想详细讲解,可以查看Jetpack之Lifecycle

3.2 源码分析

了解了这几个类的基本关系,接下来重点分析一下LiveData,根据使用的三步来分析第一步:创建LiveData

3.2.1 创建过程分析
public abstract class LiveData {
    // liveData持有的数据
    private volatile Object mData;
    // mVersion可以理解为mData的版本,即更新次数,会作为是否通知观察者的判断依据;只增不减
    private int mVersion;
    // 初始默认版本
    static final int START_VERSION = -1;
    // 空对象
    static final Object NOT_SET = new Object();
    
    // 带参构造函数,同时mVersion版本 +1
    public LiveData(T value) {
        mData = value;
        mVersion = START_VERSION + 1;
    }

    // 无参构造函数,mData赋值默认数据,mVersion为初始版本
    public LiveData() {
        mData = NOT_SET;
        mVersion = START_VERSION;
    }
}
3.2.2 监听(观察)过程分析
(1)注册观察者

LiveData提供了两个观察方法observe(...)observeForever(...),其中observeForever(...)与生命周期无关也比较简单,看一下LiveData关于该方法的源码:

public abstract class LiveData {
    // 观察者集合
    private SafeIterableMap, ObserverWrapper> mObservers = new SafeIterableMap<>();
    // 该方法必须在主线程调用
    @MainThread
    public void observeForever(@NonNull Observer observer) {
        // 判断是否在主线程,若不在则抛异常
        assertMainThread("observeForever");
        // 将观察者包装到AlwaysActiveObserver
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        // 将包装后的观察者添加到观察者列表中;若已添加则返回该对象,若未添加在则添加并返回为空
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        // 如果观察者为LifecycleBoundObserver则抛异常,同一个观察者observer不能被包装2次,
        if (existing instanceof LiveData.LifecycleBoundObserver) {
            // 翻译一下:不能添加具有不同生命周期的同一个观察者 
            throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
        }
        // 如果不为空则表示添加过(mObservers内已存在),直接返回;为空则表示第一次添加,需要执行后面的逻辑
        if (existing != null) {
            return;
        }
        // 此处为第1中情况调用activeStateChanged()方法
        // * 状态改变,正是由于这句代码带来了粘性效果;由于该类没有关联生命周期所以默认观察者始终处于活跃状态,故直接调用并传递 true
        wrapper.activeStateChanged(true);
    }
    
    private abstract class ObserverWrapper {
        // 被包装的观察者
        final Observer mObserver;
        // 观察者是否处于或者状态的标记变量
        boolean mActive;
        // 观察者观察到的数据版本
        int mLastVersion = START_VERSION;
        // other code ...
        // 该方法作用类似于mActive,但比mActive更精确;由子类实现
        abstract boolean shouldBeActive();
        
        // 是否关联到入参的生命周期;默认为false
        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }
        
        // 解除观察者
        void detachObserver() {
        }
        
        // 有4种情况会调用该方法:1.observeForever初次添加观察者时;2.数据变更时;3.移除观察者时;4.生命周期改变时;
        void activeStateChanged(boolean newActive) {
            // 新状态和当前状态一致则不处理
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive owner
            // 翻译一下:立即设置活动状态,这样我们就不会将任何东西分派给不活动的所有者 
            // 意思是:先改状态后分发,为什么不是先分发再改状态呢?
            // 举例旧状态为true新状态为false,先分发的情况下,mActive还未被赋予新状态,此时仍是ture,则同样会执行dispatchingValue()方法,若先赋值则不存在该情况
            mActive = newActive;
            // 调用外部类的方法,内部会经过判断调用liveData 的 onActive()或onInactive()方法,表示当前观察者是否处于活跃状态
            changeActiveCounter(mActive ? 1 : -1);
            // 若状态未活跃,则分发数据
            if (mActive) {
                // * 分发数据
                dispatchingValue(this);
            }
        }
    }
    
    // 该类未覆盖父类的 detachObserver() 方法
    private class AlwaysActiveObserver extends ObserverWrapper {

        AlwaysActiveObserver(Observer observer) {
            super(observer);
        }

        // 这里固定返回为ture,即表示观察者一直为活跃状态
        @Override
        boolean shouldBeActive() {
            return true;
        }
    }
}

上面分析了observeForever(...)方法,注意activeStateChanged(boolean newActive)有4种情况会调用:

  1. observeForever初次添加观察者时(上已经介绍,粘性效果的关键)

  2. 数据变更时,根据实时状态判断调用

  3. 移除观察者时

  4. 观察者生命周期改变时

这里记住在无关联生命周期的方法observeForever(...)的内部会调用到dispatchingValue(this)方法;

接下来看一下看一下LiveData关于observe()方法的源码:

public abstract class LiveData {
    // 观察者集合
    private SafeIterableMap, ObserverWrapper> mObservers = new SafeIterableMap<>();
    // 该方法必须在主线程调用;接收生命周期持有者和观察者2个参数
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
        // 判断是否在主线程,若不在则抛异常
        assertMainThread("observe");
        // 判断需要关联的生命周期持有的状态,如果为DESTROYED状态则不处理;即已经销毁的观察者没有必要再观察数据
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        // 将观察者包装到 LifecycleBoundObserver
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        // 将包装后的观察者添加到观察者列表中;若已添加则返回该对象,若未添加在则添加并返回为空
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        // mObservers内已存在并且不是同一生命周期持有者则抛异常;即同一观察者不能关联不同的生命周期持有者
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
        }
        // 如果不为空则表示添加过(mObservers内已存在),直接返回;为空则表示第1次添加,需要执行后面的逻辑
        if (existing != null) {
            return;
        }
        // 第1次添加该观察者,则将其与生命周期关联
        owner.getLifecycle().addObserver(wrapper);
    }
    
    
    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;
        // 省略其他代码
        // 判断观察者状态是否为活跃状态;LiveData 感知生命周期的关键也是这里
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        // 当生命周期组件(Activity、Fragment等)状态发生改变时(create、resume等)会触发该方法;更多内容需了解Lifycycle知识
        // observe()是在onCreate时调用,而observe()内部添加了生命周期变化的感知能力。那么在Lifecycle.Event为onCrate时,这里是否能接收到回调呢?答案是可的,因为onCrate事件是在Activity等执行完之后,才会通知观察者
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                                   @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            // 生命周期处于DESTROYED时,移除观察者并返回;而其他状态则会继续执行
            if (currentState == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            // 这里的 currentState 和 prevState 都为局部变量;为什么要创建prevState并赋值呢?了解的小伙伴指导一下...
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
                prevState = currentState;
                // * 这里是第4种情况下调用activeStateChanged()方法,若数据已经发生变化,即使刚刚添加的观察者也可以收到新数据(LiveData的粘性效果)
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

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

        // 解除观察者
        @Override
        void detachObserver() {
            // 从生命周期中移除观察者
            mOwner.getLifecycle().removeObserver(this);
        }
    }
}

LiveData感知生命周期的能力关键在于owner.getLifecycle().addObserver(wrapper);,上面分析了观察者生命周期改变时会调用activeStateChanged()方法,且在Activity的onCreate中添加观察者依旧可以接收到改变后的数据(粘性效果)。

总结一下注册观察者:在注册观察者时会根据调用不同的方法将观察者包装到不同的wapper中,添加到观察者集合里,并调用分发数据方法通知观察者最新数据(若有),达到粘性效果。

(2)dispatchingValue(...)分析

上面分析了2种调用activeStateChanged(boolean newActive)的情况:

  1. observeForever初次添加观察者时
  1. 观察者生命周期改变时

接下来分析一下该方法内部的关键方法dispatchingValue(),该方法在setValue()方法内也会调用。

public abstract class LiveData {
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    /*
    * 分发数据,在数据发生改变或生命周期发生改变等情况下会调用该方法
    * 接收一个观察者参数
    */
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            // 若传入的指定观察者不为空则通知指定观察者
            if (initiator != null) {
                // 通知观察者
                considerNotify(initiator);
                initiator = null;
            } else {
                // 若传入的指定观察者为空,则通知观察者集合(mObservers)里面的所有观察者
                for (Iterator, ObserverWrapper>> iterator =
                     mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    // 通知观察者
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
    
    // 通知观察者
    private void considerNotify(ObserverWrapper observer) {
        // 如果观察者不活跃则直接返回
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        // 直译:也许它改变了状态,但我们还没有得到事件。 我们仍然首先检查[observer.active]以保持它作为事件的入口。 因此,即使观察者移动到活动状态,如果我们没有收到该事件,我们最好不要通知。 
        // 也就是说:观察者内部的成员变量 mActive 可能已经改变为活跃状态,但是还没有收到生命周期组件的事件通知;即加此判断可以保证更加准确的获取观察者的实时状态。
        if (!observer.shouldBeActive()) {
            // 纠正观察者的正确状态;第2种情况调用activeStateChanged()方法
            observer.activeStateChanged(false);
            return;
        }
        // 若之前的版本号高于或等于当前版本号则直接返回;只有当前版本大于旧版本时才继续执行;mVersion 该变量会在每次 setValue 时 +1
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        // 通知观察者数据已更新
        observer.mObserver.onChanged((T) mData);
    }
}
(3)注销观察者

注销观察者也有2个方法:

public abstract class LiveData {
    // 移除指定观察者
    @MainThread
    public void removeObserver(@NonNull final Observer observer) {
        // 判断是否在主线程,不在则抛异常
        assertMainThread("removeObserver");
        // 从观察者列表中移除
        ObserverWrapper removed = mObservers.remove(observer);
        if (removed == null) {
            return;
        }
        // 已移除的观察者解除对生命周期组件的关联
        removed.detachObserver();
        // 移除的观察者置为非活跃状态;第3种情况调用activeStateChanged()方法
        removed.activeStateChanged(false);
    }

    /**
     * 移除给定生命周期组件所关联的所有观察者
     */
    @SuppressWarnings("WeakerAccess")
    @MainThread
    public void removeObservers(@NonNull final LifecycleOwner owner) {
        // 判断是否在主线程,不在则抛异常
        assertMainThread("removeObservers");
        // 遍历观察者列表
        for (Map.Entry, ObserverWrapper> entry : mObservers) {
            // 如果是与给定的观察者一致,则调用 removeObserver(...)方法
            if (entry.getValue().isAttachedTo(owner)) {
                removeObserver(entry.getKey());
            }
        }
    }
}

注册、注销观察者的流程就分析完了,关于前面问题提到的粘性效果在分析过程中也提到了,即在注册观察者时调用了通知观察者数据改变的方法。那么能否去掉粘性效果呢?如何去掉?

首先通过上面的分析可以知道,在真正调用观察者的onChange(T)之前会有3次判断,可以通过改变其中1个的判断条件即可:

// 通知观察者
private void considerNotify(ObserverWrapper observer) {
    // 第1次判断
    if (!observer.mActive) {
        return;
    }
    // 第2次判断
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    // 第3次判断
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

前2次判断都是和观察者的活跃状态有关,而这个活跃状态和生命周期相关,不能轻易修改。第3次判断数据版本看起来可行,它本身就是标记数据版本的,那么久从它下手。

粘性效果是指:数据先发生改变,后注册观察者也可以收到数据改变。数据发生了改变,其持有的成员变量private int mVersion就大于0;而后注册观察者,在观察者包装类中的成员变量被赋值为int mLastVersion = START_VERSION(-1)observer.mLastVersion >= mVersion条件不成立,故会通知观察者。去掉粘性效果:在注册时将mVersion的值赋值给mLastVersion即可使该条件成立,不再通知观察者。附上一段大神的实现:

public class UnPeekLiveData extends MutableLiveData {

    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
        super.observe(owner, observer);
        hook(observer);
    }

    private void hook(Observer observer) {
        Class liveDataClass = LiveData.class;
        try {
            //获取field private SafeIterableMap, ObserverWrapper> mObservers
            Field mObservers = liveDataClass.getDeclaredField("mObservers");
            mObservers.setAccessible(true);
            //获取SafeIterableMap集合mObservers
            Object observers = mObservers.get(this);
            Class observersClass = observers.getClass();
            //获取SafeIterableMap的get(Object obj)方法
            Method methodGet = observersClass.getDeclaredMethod("get", Object.class);
            methodGet.setAccessible(true);
            //获取到observer在集合中对应的ObserverWrapper对象
            Object objectWrapperEntry = methodGet.invoke(observers, observer);
            Object objectWrapper = null;
            if (objectWrapperEntry instanceof Map.Entry) {
                objectWrapper = ((Map.Entry) objectWrapperEntry).getValue();
            }
            if (objectWrapper == null) {
                throw new NullPointerException("ObserverWrapper can not be null");
            }
            //获取ObserverWrapper的Class对象  LifecycleBoundObserver extends ObserverWrapper
            Class wrapperClass = objectWrapper.getClass().getSuperclass();
            //获取ObserverWrapper的field mLastVersion
            Field mLastVersion = wrapperClass.getDeclaredField("mLastVersion");
            mLastVersion.setAccessible(true);
            //获取liveData的field mVersion
            Field mVersion = liveDataClass.getDeclaredField("mVersion");
            mVersion.setAccessible(true);
            Object mV = mVersion.get(this);
            //把当前ListData的mVersion赋值给 ObserverWrapper的field mLastVersion
            mLastVersion.set(objectWrapper, mV);

            mObservers.setAccessible(false);
            methodGet.setAccessible(false);
            mLastVersion.setAccessible(false);
            mVersion.setAccessible(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
3.2.3 更新 LiveData 对象分析

分析一下更新LiveData持有的数据源码:

public abstract class LiveData {
    // 延迟的数据
    volatile Object mPendingData = NOT_SET;
    private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                // 将延迟数据赋值给局部变量newValue
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            // 将newValue作为入参调用setValue方法
            setValue((T) newValue);
        }
    };
    // 可以在子线程调用
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            // 将数据赋值给延迟数据mPendingData
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        // 内部会追溯到 DefaultTaskExecutor ,是通过 Handler 实现的调度
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
    
    // 必须在主线程调用
    @MainThread
    protected void setValue(T value) {
        // 判断是否在主线程,否则抛异常
        assertMainThread("setValue");
        // 数据版本 +1
        mVersion++;
        // 给数据赋值
        mData = value;
        // 分发数据;内部分析查看 [dispatchingValue(...)分析]
        dispatchingValue(null);
    }
}

问题:

分析如下代码,分析观察者收到的数据( ):

// 在主线程按如下顺序调用
liveData.postValue("a");
liveData.setValue("b");

A. a
B. b
C. a b
D. b a

解析:更新了2次数据且调用的是不同方法,所以首先排除 A B ;接着分析顺序,由于setValue(T)是直接通知更新,所以观察者会首先收到 ‘b’ ;postValue(T)是将新数据赋值给mPendingData,等到Handler调度执行时才会调用setValue(T)mPendingData的数据通知给观察者,故'a'后收到。答案:D.
源码注释中还有:如果在主线程执行提交的任务之前多次调用此方法,则只会分派最后一个值。也比较容易理解,"主线程执行提交的任务之前多次调用此方法"mPendingData会一直被赋值为新值,在执行调度时也只有最后一个值会被分派。

你可能感兴趣的:(Jetpack之LiveData)