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<String> by lazy {
        MutableLiveData<String>()
    }
}

最初,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<String> { 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<? super T> observer)方法向其成员变量SafeIterableMap<Observer<? super T>, 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<T> {
    // 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<T> {
    // 观察者集合
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
    // 该方法必须在主线程调用
    @MainThread
    public void observeForever(@NonNull Observer<? super T> 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<? super T> 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<? super T> 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<T> {
    // 观察者集合
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
    // 该方法必须在主线程调用;接收生命周期持有者和观察者2个参数
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> 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<T> {
    @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<Map.Entry<Observer<? super T>, 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<T> {
    // 移除指定观察者
    @MainThread
    public void removeObserver(@NonNull final Observer<? super T> 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<Observer<? super T>, 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<T> extends MutableLiveData<T> {

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

    private void hook(Observer<? super T> observer) {
        Class<LiveData> liveDataClass = LiveData.class;
        try {
            //获取field private SafeIterableMap<Observer<T>, 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<T> {
    // 延迟的数据
    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会一直被赋值为新值,在执行调度时也只有最后一个值会被分派。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容