LiveData作为jettpack的一环,常搭配ViewModel一起使用;相比于RxJava,用LiveData封装的LiveDataBus更加简洁方便,并且LiveData会感知页面的信息变化,当页面是不可见的时候,及时Data有数据更新,页面也不会接收到,然后在页面重新可见再去把数据通知给页面,而且在页面销毁时也会及时销毁数据,大大降低了内存泄露的发生;这篇主要简单分析一下LiveData的流程
1.LiveData的使用
class TestActivity :AppCompactActivity(){
var statusData: MutableLiveData = MutableLiveData()
override fun onCreate(savedInstanceState: Bundle?) {
...
statusData.observe(this, this)
}
override fun onChanged(t: TestLiveStatus?) {
Log.e("TAG", "onChanged -> $t ");
}
}
使用很方便,只需要注册一个监听,然后在监听里处理状态变化就可以
2.LiveData源码分析
2.1 livedata的注册
@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);
}
LifeCycle是页面的生命周期监听,主要是通过在Activity里面添加一个空的ReportFragment,监听这个Fragment的状态来实现;具体我会在下一篇中描述,这里只需要知道这个可以感知Activity的生命周期即可
这里先会创建一个LifeCycleBoundObserver ,并把owner和observer都传进去,然后用mObserv
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
这里主要关注两个方法shouldBeActive和onStateChanged
shouldBeActivite个枚举判断,如果枚举的类型比STARTED大则返回true
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
我们看一下这个State的声明
public enum State {
DESTROYED,
INITIALIZED,
CREATED,
STARTED,
RESUMED
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
}
比STARTED大的只有RESUME
LifeCycle和这个State的有个对应关系可以参考一下,所以我们可以认为这个shouldBeActive返回的是表示是页面是否是从不可见变成了可见状态
static State getStateAfter(Event event) {
switch (event) {
case ON_CREATE:
case ON_STOP:
return CREATED;
case ON_START:
case ON_PAUSE:
return STARTED;
case ON_RESUME:
return RESUMED;
case ON_DESTROY:
return DESTROYED;
case ON_ANY:
break;
}
throw new IllegalArgumentException("Unexpected event value " + event);
}
onStateChanged中包含两部分
1.当页面被销毁时,注册的观察者被清除,后续的事件通知也随之终止
2.当页面非销毁状态时,处理相应的状态变化逻辑
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;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}
可以看出,这个方法只处理活跃状态变化的,而从上面的分析,可以认为就是页面可见性变化的处理
默认mActiveCount = 0 , 每次从不可见变成可见+1,而从可见变成不可见-1
onActive和onInactive则分别是处理这两种状态的方法,这里这两个都是空实现
最后的当变成可见后 会调用 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, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
这里虽然有改while循环,但大部分情况下只会执行一次,因为mDispatchInvalidated一进来就会设置成false ; 对于并发情况会执行多次,因为在入口处并发会重新设置成true
有两种情况,initiator为空和不为空,为空是通知所有的观察者,不为空则是通知传入的initiator;
主要差异是主动和被动
为null主要场景是setValue等主动设置值的情况,会同步更新所有注册的监听
不为null的主要场景是状态变更,每个observer自己去刷新数据
然后我们看一下considerNotify方法
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;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
这里会先判断是否是活跃的,不活跃的直接返回
再判定状态是否resume的,不是的话就回到上面的状态变更方法;这里相当于做了活跃的二次判断
然后判断mLastVersion和mVersion的大小,只有mVersion比mLastVersion大才会去通知observer去观察数据,同时把mLastVersion赋值成新的值;这个主要是避免重新分发,如果没这个判断,则每次从不可见变成可见都会分发一次最新的消息,这肯定不是我们所想要的结果
然后设置值的方法
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
在这里会把mVersion++ , 并调用上面的dispatchingValue(null)方法通知所有的observer
注意的是
static final int START_VERSION = -1;
private int mVersion = START_VERSION;
private abstract class ObserverWrapper {
int mLastVersion = START_VERSION;
...
}
初始值mVersion和mLastVersion都是 -1 ,而LiveData有两个构造方法区别一下
public LiveData(T value) {
mData = value;
mVersion = START_VERSION + 1;
}
/**
* Creates a LiveData with no value assigned to it.
*/
public LiveData() {
mData = NOT_SET;
mVersion = START_VERSION;
}
无参的构造方法mVersion=-1,而传一个data数据的mVersion=0
就是说,有数据的构造方法,初始值判断 mVersion> mLastVersion是成立的,而无参的是不成立的
此外,因为setValue会使mVersion++, 如果在注册观察者之前就调用了setValue方法,那么在注册后,页面变成可见的情况下,会强制把之前set的值刷新到方法回调中,正常来说没有问题;
但在我们设计LiveDataBus总线消息机制的时候,很明显是不符合消息的流程的,不论是Rxjava还是EventBus都是不允许接收到注册前的信息的
具体修改得依赖反射,自定义LiveData继承自MutableLiveData,重写observer方法
@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);
}
反射修改LiveData的mVersion值,然后通过反射拿到wrapper对象,反射修改这个对象的mLastVersion值
常规LiveDataBus配置
public class LiveDataBus {
private static LiveDataBus instance = new LiveDataBus();
private Map map = new HashMap<>();
public static LiveDataBus getInstance() {
return instance;
}
public MLiveData getLiveData(String key, Class type) {
if (!map.containsKey(key)) {
map.put(key, new MLiveData());
}
return (MLiveData) map.get(key);
}
public void remove(String key) {
map.remove(key);
}
}
public class MLiveData extends MutableLiveData {}
页面配置
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_data_bus);
findViewById(R.id.btn_click).setOnClickListener(this);
textView = findViewById(R.id.tv_msg);
liveData = LiveDataBus.getInstance().getLiveData("1234", String.class);
liveData.setValue("aaa");
liveData.setValue("bbbb");
liveData.observe(this, x -> {
textView.setText(x + "");
}
);
}
这时候进来,页面会直接显示文字 "bbbb" ,但我们注册是在发送之后,不应该接收到前面的消息
然后我们反射修改成这个样式就可以了
public class MLiveData extends MutableLiveData {
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
super.observe(owner, observer);
reflect(observer);
}
private void reflect(Observer observer) {
try {
Field mObserversField = LiveData.class.getDeclaredField("mObservers");
mObserversField.setAccessible(true);
Object mObservers = mObserversField.get(this);
Method getMethod = mObservers.getClass().getDeclaredMethod("get", Object.class);
getMethod.setAccessible(true);
Object observerEntry = getMethod.invoke(mObservers, observer);
//这个值获取到的是 SafeIterableMap.Entry 实现了Map.Entry接口,需要再次获取
//而HashMap中
// public V get(Object key) {
// Node e;
// return (e = getNode(hash(key), key)) == null ? null : e.value;
//}
// 可以看出帮我们自动获取了value的属性
Map.Entry entry = (Map.Entry) observerEntry;
Object observerWrapper = entry.getValue();
Field mLastVersionField = observerWrapper.getClass().getSuperclass().getDeclaredField("mLastVersion");
mLastVersionField.setAccessible(true);
Field mVersionField = LiveData.class.getDeclaredField("mVersion");
mVersionField.setAccessible(true);
Object mVersion = mVersionField.get(this);
mLastVersionField.set(observerWrapper,mVersion);
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意mObserver的get方法获取到的并不是实际的值
private SafeIterableMap, ObserverWrapper> mObservers =
new SafeIterableMap<>();
这个集合的get方法返回的是一个节点的信息
protected Entry get(K k) {
Entry currentNode = mStart;
while (currentNode != null) {
if (currentNode.mKey.equals(k)) {
break;
}
currentNode = currentNode.mNext;
}
return currentNode;
}
需要再次调用获取value方法获取真正的值
而HashMap中
public V get(Object key) {
Node e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
可以看出帮我们自动获取了value的属性,这两点区分一下
LiveData中有一个额外的注册方法,observerForever方法,注意这里不需要LifecycleOwner传入,是和页面无关的,而且一注册马上会调用activeStateChanged(true)方法,上面也说到了,这里就认为页面从不活跃变更为活跃状态,并把活跃值置为true,因为是周期无关,这个值后续一直会是true, 而在这里的方法相当于马上接收到最新的消息;
@MainThread
public void observeForever(@NonNull Observer super T> observer) {
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
wrapper.activeStateChanged(true);
}
而且这个类的活跃判断方法被重写为true
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer super T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
return true;
}
而在上面的considerNotify方法中,这两个方法的判定就始终是不满足的,所以一直会执行消息发布
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
1.通过observe方法注册并传入当前Activity信息,可以感知当期页面生命周期变化;
当页面销毁时候清除所有注册并直接退出;
当页面从不可见变成可见时,检测数据的Version, 根据具体的比较值判断是否发送最新消息给观察者对象,判断标准是当mVersion> mLastVersion 则发送,并把mLastVersion同步成mVersion值,而这两个对应的初始值都是-1;
mVersion归属LiveData,而mLastVersion归属ObserverWrapper,对应于上面创建的LifecycleBoundObserver,反射时候需要注意;
引入Version判断是为了避免重复发送数据,当活跃状态频繁变更而数据未变更导致的多次刷新;
可见性状态判断只要是根据声明的枚举类型,当前状态和STARTED状态进行对比,大于这个状态即RESUME状态则认为是从不可见变成可见,反之则是可见变成不可见,这个属于被动更新;可见性又可以称为活动状态,意思都差不多
2. 通过setValue或postValue方法通知所有注册的观察者数据发生了更新,这个是主动更新,但仍受页面可见性状态影响,非可见状态并不会通知数据更新,需要等下次页面活动状态变更才去刷新;
每次通知都会把当前LiveData的数据版本mVersion++,不论是被动还是主动更新都必须满足version判定规则;
setValue在主线程中调用,postValue在子线程中调用
3.当注册前就已经发送了消息更新数据,那么注册后第一次活跃状态变更就会把这个数据刷新给观察对象;
正常流程无需关心,但涉及消息总线处理则需要额外反射处理LiveData,一般自定义继承MutableLiveData,在注册的时候将传入的对象的observer中的mLastVersion更改为LiveData中的mVersion值,这样注册之前的数据变更消息便不会接收
4.如果不需要关注页面信息,只用来提示消息更新,则可以用observerForever方法
补上一张大致关系图