简述
LiveData是一个可被观察的数据容器类,它将数据包装起来,使数据成为被观察者。当数据发生改变时,观察者能够及时得到通知。又是一个典型的观察者模式!
ViewModel用来存放页面所需要的数据、和数据相关的处理逻辑(在ViewModel中对数据进行加工、获取),站在页面的角度上,它并不关心ViewModel的业务逻辑,只关心需要展示的数据是啥。它希望在数据发生改变时,能够及时的得到通知并作出更新。而LiveData的作用就是在ViewModel中的数据变化时,去及时的通知页面。因此LiveData通常和ViewModel组合使用。
LiveData原理
首先需要创建一个观察者来观察对象:
//需要一个观察者来观察数据,被观察者有啥举动,观察者这边及时的onChanged作出改变
Observer observer=new Observer<String>(){
@Override
public void onChanged(String s) {
tv.setText(s);
}
};
然后作出订阅:
//订阅
model.getCurrentName().observe(this,observer);
1.订阅、绑定
通过observe方法进行订阅绑定:
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
//判断是否主线程,否则就抛出异常
assertMainThread("observe");
//判断状态,如果DESTORYED就return不管。因为此时Activity没用,根本没必要管
//Activity能用,才会继续往下走
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//将观察者、被观察者统一封装到LifecycleBoundObserver中
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//将Observer、LifecycleBoundObserver对象包装放到Entry<Observer,LifecycleBoundObserver对象>中
//先get(key)查,有就return返回。没有再put
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;
}
//调Lifecycle的addObserver方法,用的还是Lifecycle的绑定流程
owner.getLifecycle().addObserver(wrapper);
}
只有在主线程、且非DESTORYED状态下,才会进行绑定。这里会将观察者、被观察者统一封装到LifecycleBoundObserver对象中,并将Observer对象、LifecycleBoundObserver对象封装到ObserverWrapper对象中。最后调用LifeCycle的addObserver方法,走的还是LifeCycle的绑定流程!
2.setValue发送消息
调用的LifeData的setValue方法:
@MainThread
protected void setValue(T value) {
//判断是否主线程
assertMainThread("setValue");
//mVersion和mLastVersion呼应
mVersion++;
mData = value;
//分发Value
dispatchingValue(null);
}
这里dispatchingValue和ConsiderNotify方法是 “飞雷神互瞬回” :
//第一次调用,传入的null,所以直接走else
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
//value不为null,直接去发送通知
considerNotify(initiator);
initiator = null;
} else {
//迭代器拿到每个观察者Observer
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
//发通知,当被观察者在setValue(value)时,要发送通知
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
然后开始“互瞬回”了considerNotify:
//关键的3个if
private void considerNotify(ObserverWrapper observer) {
//如果Observer不是活动状态,退出
if (!observer.mActive) {
return;
}
//如果不应该被激活,就进入if
//如果当前Activity的最后一个状态,在经历过CompareTo后返回true,即比STARTED大(RESUMED),
//就跳过走下一个if
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
//用mActiveCount统计有多少个会处于活动状态
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
//最后“互瞬回”去分发
dispatchingValue(this);
}
}
“飞雷神互瞬回”循环的目的:找到1个正在前台的Activity。关于mVersion和mLastVersion,他们的初始值都是-1。LiveData—>mVersion只有一个(mVersion++),但是Observer—>mLastVersion有多个(mLastVersion=mVersion)。只要setValue一次,就会触发一次mVersion++,Observer.mObserver.onChanged—>最新的一次发消息。considerNotify通知方法的3次if,前2次是判断状态,第3次是判断mVersion和mLastVersion,这是处于性能考虑(一个Thread向Activity发送消息,如果发送60次,但Activity不可见,此时不需要接受处理。当发送第61次时Activity可见,此时接收处理正好)。
LiveData帮我们处理了容错,自己虽然可以实现,但是各种引用满天飞,肯定会内存泄漏。LiveData利用观察者模式,帮我们规避了OOM.
3.总结
LiveData的订阅、绑定,实际上用的还是LifeCycle的绑定流程。使用setValue发送消息,有个很有意思的地方,就是dispatchingValue分发和considerNotify通知的相互调用。分发时首先通过迭代遍历拿到所有的观察者Observer,并发送通知。执行通知方法时会经历3个if判断,不满足条件就又跑回去执行分发了。这样折腾的目的就是为了要找到一个正在前台的Activity,然后执行 observer.mObserver.onChanged((T) mData)方法,这样我们在观察者重写的onChanged方法就会被执行。
LiveData帮我们处理了容错,虽然可以自己实现,但是各种引用满天飞肯定会造成内存泄漏。LiveData利用观察者模式,帮我们完美的规避了这个问题。