Jetpack之LiveData
1. 介绍
LiveData 具有生命周期感知能力,学习LiveData之前最好了解一下Lifecycle的知识,以下是来自官网的介绍:
LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。 如果观察者(由 Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。
使用 LiveData 具有以下优势:
确保界面符合数据状态 LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知 Observer 对象。您可以整合代码以在这些 Observer 对象中更新界面。这样一来,您无需在每次应用数据发生变化时更新界面,因为观察者会替您完成更新。
不会发生内存泄漏 观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。
不会因 Activity 停止而导致崩溃 如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。
不再需要手动处理生命周期 界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。
数据始终保持最新状态 如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。
适当的配置更改 如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。
共享资源 您可以使用单例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象。
2. 使用
使用LiveData分为创建、监听(观察)、通知(更新)三个步骤:
- 创建 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 对象在配置更改后继续存在。
- 观察 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是有粘性的。
- 更新 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
根据前面的介绍,思考几个问题:
LiveData如何做到仅更新处于活跃生命周期状态的应用组件观察者?
LiveData粘性效果是怎么实现的?能否去掉?如何去掉粘性效果?
LiveData中的setValue(T)和postValue(T)有什么区别?内部分别怎么实现的?
3.1 LiveData的相关类和结构
首先看一下源码包,基于androidx.lifecycle:lifecycle-livedata-core:2.3.1
:
可以看到源码包中的类出奇的少,但是其内部用到了Lifecycle的相关类,看一下类图:
LiveData本身是一个很简单的观察者模式,通过observe(LifecycleOwner owner, @Observer super T> observer)
方法向其成员变量SafeIterableMap
添加观察者,在数据发生改变时调用setValut(T)
或postValue(T)
来通知观察者发生数据改变。
那么LiveData如何做到仅更新处于活跃生命周期状态的应用组件观察者,原理也比较简单,维护一个成员变量boolean mActive
,在通知观察者之前判断该变量为true
时则通知,否则不通知。而boolean mActive
表示了观察者当前是否为活跃状态,这个状态的改变则依赖于Lifecycle
生命周期组件。
- Observer
Observer
只有一个方法的观察者,LiveData发生变化时通知的就是它。
- LiveData
关键类,所有关键源码也基本上在这个类里,后面分析源码时详细讲解:
内部维护了观察者列表、提供了添加观察者的方法、数据更新方法(通知观察者);
一个内部抽象类
ObserverWrapper
,关键变量boolean mActive
由它维护;两个内部类
LifecycleBoundObserver
和AlwaysActiveObserver
,类图中有说明区别;
- MutableLiveData
由于LiveData
中的 setValue(T)
和postValue(T)
是protected
,外部无法访问,那么该怎么更新内容呢?Android提供了MutableLiveData
,该类目前也只有一个作用,即将 setValue(T)
和postValue(T)
方法公开public
。
LifecycleObserver
和LifecycleEventObserver
是Lifecycle
的知识,这里不想详细讲解,可以查看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 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种情况会调用:
observeForever初次添加观察者时(上已经介绍,粘性效果的关键)
数据变更时,根据实时状态判断调用
移除观察者时
观察者生命周期改变时
这里记住在无关联生命周期的方法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 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)
的情况:
- observeForever初次添加观察者时
- 观察者生命周期改变时
接下来分析一下该方法内部的关键方法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 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, 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 super T> observer) {
super.observe(owner, observer);
hook(observer);
}
private void hook(Observer super T> 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
会一直被赋值为新值,在执行调度时也只有最后一个值会被分派。