Android~LiveData原理

mVersion++;

mData = value;

dispatchingValue(null);

}

private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =

new SafeIterableMap<>();

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;

}

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

这里的mObservers是一个SafeIterableMap迭代器实现的HashMap容器,它是由ObserverWrapper构成,ObserverWrapper又包含了Observer接口实现。它内部调用ObserverWrapper对象判断,自带的属性mActive和mLastVersion,最终调用mObserver的onChanged,下发到具体的观察者。

postValue用于在异步线程中调用,内部则使用了对象锁,更新mPendingData取出数据最终setValue。

private final Runnable mPostValueRunnable = new Runnable() {

@SuppressWarnings(“unchecked”)

@Override

public void run() {

Object newValue;

synchronized (mDataLock) {

newValue = mPendingData;

mPendingData = NOT_SET;

}

setValue((T) newValue);

}

};

protected void postValue(T value) {

boolean postTask;

synchronized (mDataLock) {

postTask = mPendingData == NOT_SET;

mPendingData = value;

}

if (!postTask) {

return;

}

ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);

}

observe

同样也是通过断言控制在主线程中执行,然后判断LifecycleOwner持有者的状态,假如不等于DESTROYED,创建LifecycleBoundObserver生命期范围的观察者,将它放到mObservers容器中,根据存放情况决定owner是否需要wrapper对象。observeForever则是用于观察不需要关联生命期类型的数据,逻辑和obseve类似只是AlwaysActiveObserver不同。

@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);

}

@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");

}

i外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

资料获取→专栏
f (existing != null) {

return;

}

wrapper.activeStateChanged(true);

}

LiveData的粘性事件

粘性事件产生的原因:LiveData天生支持粘性事件,因为它的实现就是这样的。大多数场合我们还是需要用到粘性事件的。如果是多个界面公用同一个ViewModel时,会出现该情况,又比如obser里面还做了一些计算或复杂的业务操作,就会有影响。

正常流程,在注册时没有收到消息。非正常的流程则是,注册之前就有消息被收到,就导致mLastVersion<mVersion,从而触发onChange最终导致了粘性事件。

mLastVersion:观察者持有,

mVersion:被观察者持有。

通信方案对比总结

| 通信方案 | 优点 | 缺点 |

| — | — | :-- |

| Handler | 系统原生,能实现线程间通信 | 高耦合

不利于维护

容易导致内存泄漏和NullPointer |

| Broadercast | 简单 | 性能差

传播数据有限

打乱代码的执行逻辑 |

| interface | 接口速度快,容易理解 | 实现起来复杂,不好维护 |

| rxBus | 效率高,无内存泄漏 | 基于RxJava,学习成本高且依赖包太大,rxJava2.2M |

| EventBus | 使用简单 | 混淆问题

无法感知组件生命周期

实现复杂。 |

组件间通信可以如何做?

static最好不要随便用,容易内存泄漏,jvm中会管理它。如果用单例不合适,单例也会导致内存常驻。广播是用来监听系统的一系列变化,LiveData不能替代广播。观察者模式可以一对多,接口回调只能一对一。关于LiveData的粘性事件,解决方法有多种,可用用反射,也可以自己实现非粘性的LiveData,本文不做详细讨论,个人觉得与其想办法处理问题,不如设计时如何规避问题更来的有效,实在应用场景确实需要再用。

参考

  1. Android消息总线的演进之路:用LiveDataBus替代RxBus、EventBus

  2. 关于 LiveData 粘性事件 的个人思考
    回调只能一对一。关于LiveData的粘性事件,解决方法有多种,可用用反射,也可以自己实现非粘性的LiveData,本文不做详细讨论,个人觉得与其想办法处理问题,不如设计时如何规避问题更来的有效,实在应用场景确实需要再用。

参考

  1. Android消息总线的演进之路:用LiveDataBus替代RxBus、EventBus

  2. 关于 LiveData 粘性事件 的个人思考

  • 23
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值