持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30天,点击查看活动详情
LiveData提供了两个方法更新数据,分别是setValue()和postValue()。
setValue
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
setValue()方法只能在主线程调用,所以一开始会检查调用的线程,然后更新版本号mVersion和数据mData,最后调用dispatchingValue分发数据。
dispatchingValue
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
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;
}
dispatchingValue()方法中使用了2个Boolean类型的变量mDispatchingValue和mDispatchInvalidated。
- mDispatchingValue 用于标记当前是否正处于分发数据的过程
- mDispatchInvalidated 用于标记当前正在分发的数据是否已经失效,在数据value还没有完全分发到所有的观察者Observer的时候,新数据已经到来,此时旧的数据就会处于失效状态。
具体分发过程中如果initiator不为null则仅向initiator分发数据。否则遍历所有的观察者并分发数据。
considerNotify
数据的回调最终由considerNotify()方法处理。
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);
}
- 首先如果观察者处于非活跃状态,直接跳过。对于AlwaysActiveObserver而言,因为他的shouldBeActive()方法返回值一直是true,所以他会一直处于活跃状态。
- 然后为了防止Lifecycle生命周期发生改变,变为不活跃状态,而LifecycleBoundObserver未及时同步状态这种情况,这里主动调用activeStateChanged()方法更新状态。
- 最有通过根据observer.mLastVersion来决定是否需要向其进行回调,防止重复向某个observer回调数据。
1,2两点保证了即使数据更新,但如果界面不处于活跃状态,也不会对数据更新做响应。第3点保证了观察者收到的数据永远都是最新的数据。
postValue
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
加锁以保证mPendingData能够一直指向最新的数据,如果postTask为false,即mPendingData != NOT_SET,说明此时有数据在回调。
由于postValue()方法没有限定调用线程,所以子线程也可以调用,但是回调方法永远是在主线程,所以会涉及到线程切换,这里通过postToMainThread()方法发送一个runnable最后使用Handler回调到主线程。
但是从子线程切到主线程之间是时间差的,在这段时间内,可能其他线程也调用了setValue()或者postValue()方法设置新的数据。这里通过加锁(synchronized (mDataLock)
)的方式保证了在mPostValueRunnable被执行前,所有通过postValue()方法传递的数据都会被保存到mPendingData中,并且只会保留最后一个,当mPostValueRunnable执行完成后,才会重置mPendingData中的数据,这保证了观察者只会收到最新的数据,但是可能会存在数据丢失的情况。
private final Runnable mPostValueRunnable = new Runnable() {
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
mPostValueRunnable用于子线程切换到主线程的时候回调数据。通过加锁保证回调的一定是最新数据。最后调用setValue()方法。