简单介绍
LiveData 是一个基于观察者模式的组件,在 Android JetPack 组件中的一部分,在开发中非常实用。LiveData 就是一个数据持有类,可以分发数据,由于内部封装了生命周期回调,所以只会在适当的生命周期中回调数据,而不会在监听者销毁后回调而导致异常。
下面我们就用一个简单的例子来分析一下 LiveData 的源码吧。
相同页面传值
我们首先在onCreate
方法中进行监听,通过点击按钮改变数据,可以看到,每次改变数据后我们的回调都会打印。
LiveDataTest.getLiveData().observe(this, {
Log.d("TAG", "MainActivity $it")
})
btnFirst.setOnClickListener {
LiveDataTest.setData("1")
}
// MainActivity 1
我们首先来看observe
方法,首先校验是否是主线程,如果宿主已经处于DESTROYED
生命周期,则直接返回。接着将宿主和回调方法封装成LifecycleBoundObserver
,然后保存回调方法和封装的wrapper
到mObservers
里面,如果回调方法已经存在且宿主不一致,说明重复提交,则会报错。如果只是回调方法存在,则直接返回。否则调用addObserver
方法,让wrapper
和宿主生命周期绑定。
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
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);
}
接着我们看setValue
的调用逻辑,也是需要在主线程调用,如果需要在子线程调用可以使用postValue
方法。接着将版本号自增,修改mData
的值,然后调用dispatchingValue(null)
方法进行数据的方法。
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
我们继续看dispatchingValue
方法,由于我们的入参是null
所以会走到 for 循环里面调用considerNotify
方法通知回调方法。
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;
}
在considerNotify
方法中,如果宿主不是活跃状态,则不会通知。然后再次检测宿主状态,接着检测版本号,然后赋值新的版本号,然后调用回调的onChanged
方法。
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.
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
不同页面传值
我们接着上面的例子,增加第二个页面,在第二个页面修改值,这是第一个页面不会收到回调方法,因为状态已经是非活跃了;接着退回到第一个页面,可以看到这时第一个页面的回调方法会被调用,因为状态已经变成活跃了。
第一个情况很好解答,因为在considerNotify
方法的第一行就做了处理,如果是非活跃的则不会回调了。第二个情况中,我们并没有再次注册,就说明LiveData
已经监听了我们的生命周期了,我们来到LifecycleBoundObserver
的类里面,可见我们宿主状态改变时会回调到onStateChanged
方法,这里面对于我们宿主的生命周期做了处理,如果已经处于销毁状态了,就会移除。如果状态改变并且是成为活跃状态了,则会调用数据回调方法,这也就解释了我们的第二种情况。