先思考几个问题
livedata是怎么做的监听生命周期的 ? postValue和setValue有什么区别 ?
事件是如何发送和接收的? livedata粘性事件是什么 ? livedata的粘性事件是怎样引起的 ?
首先需要知道注册监听和发送事件的几个方法 observe,postvalue,setvalue,我们主要是对这几个方法进行分析
发送事件
livedata发送事件的方法有两种 postValue和setValue 我们先来看setValue
- 直接调用到了MutableLiveData的setValue,MutableLiveData是LiveData的具体实现类,把Livedata复制的代码隐藏,只暴露用户需要的几个方法
@Override
public void setValue(T value) {
super.setValue(value);
}
- 调用到了父类的setValue方法,注意 mVersion++ 和 dispatchingValue方法,并且把需要发送的value值保存到了mData中
@MainThread
protected void setValue(T value) {
assertMainThread("setValue"); // 确保是在主线程,否则抛出异常
mVersion++; // 版本号加1,这里很重要
mData = value; // 保存值
dispatchingValue(null); // 分发消息(注意这个方法)
}
setValue看完了,接下来看postValue
@Override
public void postValue(T value) {
super.postValue(value);
}
- 先通过锁的方式用一个中间变量存储value,然后传递了一个Runnable给ArchTaskExecutor执行器去执行,看mPostValueRunnable具体实现,也很简单,就是把先前存的data取出来,然后调用setValue去发送消息
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) { // 保证线程安全,保存value值
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
- 我们知道了runable里面其实也是调用了setValue,重点看postToMainThread做了什么。往下找,在子类DefaultTaskExecutor实现了该方法,这里其实是拿到了主线程的handler,然后把之前的runable post出去,这样就实现了切换至线程
@Override
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = createAsync(Looper.getMainLooper());
}
}
}
//noinspection ConstantConditions
mMainHandler.post(runnable);
}
总结 : postValue其实也是通过的setValue发送消息,不同的是,postValue通过handler进行了线程切换,这样在子线程中发送消息也不会报错,而setValue会直接抛出异常
事件接收
看完了事件的发送,我们来看事件接收,注意到上面发送事件时会调用到dispatchingValue方法,这个很关键
要分析事件的接收,我们首先来看是如何注册监听的
- 传入了两个参数,生命周期的持有者和一个observer观察回调方法,然后创建了LifecycleBoundObserver对象,将生命周期持有者和observer打包,最后调用addObserver给持有者添加了该对象,这里好像看不出如何接收value的,我们点进去看LifecycleBoundObserver的具体实现。
- 这里livedata是被观察者,mObservers是观察者集合,每次调用observe就相当于往mObservers集合中添加了一个观察者,代码中表现为
mObservers.putOfAbsent
@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);
}
- 非常高兴的找到了onStateChanged方法,这不就是lifecycle的状态回调方法吗,当生命周期状态发生改变,变成活跃状态时会调用到activeStateChanged
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
- 再次判断了当前生命周期状态,如果是活跃状态,看到了我们上面提到的dispatchingValue方法,注意这里传的是this,而之前的setValue传的是null
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
dispatchingValue(this);
}
}
- 下面的if else分别对应了生命周期状态改变流程和事件接收流程,看两个流程的区别,事件接收时会遍历mObservers整个观察者列表,然后调用considerNotify,再来看看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;
}
- 上面的一些检查代码不管,看最下面几行,先判断当前观察者的版本和livedata的版本,然后将两个版本进行同步,最后调用我们之前写的observer回调,mData就是我们之前setValue的时候存的值,至此接收事件完成
- mLastVersion 和 mVersion分别用于标识最后一次observe进行回调的版本和livedata最后一次发送数据的版本,初始值均为-1,每次发送数据mVersion++,每次接收数据同步mLastVersion和mVersion
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);
}
粘性事件是什么
所谓的粘性是数据发送早于注册监听,当我们进行注册observe时,回调了上一次的老数据,从代码的层面来看,先调用了setValue将mVersion进行++,然后注册监听,当生命周期活跃时,会调用到considerNotify,而此时的mLastVersion时初始值-1,if条件不成立,进而调用onChanged接收了上一次数据
这里得满足两个条件会触发粘性事件 1.数据发送早于注册监听 2.监听者的owner生命周期进入活跃状态
livedata是被观察者,mObservers是观察者集合 要注意,mVersion存放在livedata中,而mLastVersion存放在livedata的被观察者中
如何解除粘性事件
从源码里分析很容易知道。我们只需要修改mLastVersion值,使得第一次的if条件成立就OK,具体的实现就是通过反射,找到ObserverWrapper修改它的mLastVersion的值 具体实现代码
- 在注册监听之后调用该hook方法即可
private fun hook(observer: Observer<*>) {
runCatching {
val liveDataClazz = LiveData::class.java
val mapClazz = SafeIterableMap::class.java
val getMethod: Method = mapClazz.getDeclaredMethod("get", Any::class.java)
getMethod.isAccessible = true
val observerField = liveDataClazz.getDeclaredField("mObservers")
observerField.isAccessible = true
val observers = observerField.get(this)
val invokeEntry = getMethod.invoke(observers, observer)
var boundObserver: Any? = null
if (invokeEntry != null && invokeEntry is Map.Entry<*, *>) {
boundObserver = invokeEntry.value
}
if (boundObserver == null) {
throw NullPointerException("boundObserver 为空")
}
val observerWrapperClazz: Class<*> = boundObserver.javaClass.superclass
val mLastVersionField: Field = observerWrapperClazz.getDeclaredField("mLastVersion")
mLastVersionField.isAccessible = true
val mVersionField: Field = liveDataClazz.getDeclaredField("mVersion")
mVersionField.isAccessible = true
val mVersionValue: Any = mVersionField.get(this)!!
mLastVersionField.set(boundObserver, mVersionValue)
}.onFailure {
it.printStackTrace()
}
}
最后放一个事件总线的Livedata封装代码
object LiveDataBus {
private val busMap: MutableMap<String, BusMutableLivedata<Any>> by lazy { HashMap() }
@Suppress("UNCHECKED_CAST")
@Synchronized
fun <T> with(key: String, type: Class<T>, isStick: Boolean = false): BusMutableLivedata<T> {
if (!busMap.containsKey(key)) {
busMap[key] = BusMutableLivedata(isStick)
}
(busMap[key] as BusMutableLivedata<T>).isStick = isStick
return busMap[key] as BusMutableLivedata<T>
}
class BusMutableLivedata<T> private constructor() : MutableLiveData<T>() {
var isStick: Boolean = false // 默认取消粘性事件
constructor(isStick: Boolean) : this() {
this.isStick = isStick
}
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, observer)
if (!isStick) {
hook(observer)
}
}
private fun hook(observer: Observer<*>) {
runCatching {
val liveDataClazz = LiveData::class.java
val mapClazz = SafeIterableMap::class.java
val getMethod: Method = mapClazz.getDeclaredMethod("get", Any::class.java)
getMethod.isAccessible = true
val observerField = liveDataClazz.getDeclaredField("mObservers")
observerField.isAccessible = true
val observers = observerField.get(this)
val invokeEntry = getMethod.invoke(observers, observer)
var boundObserver: Any? = null
if (invokeEntry != null && invokeEntry is Map.Entry<*, *>) {
boundObserver = invokeEntry.value
}
if (boundObserver == null) {
throw NullPointerException("boundObserver 为空")
}
val observerWrapperClazz: Class<*> = boundObserver.javaClass.superclass as Class<*>
val mLastVersionField: Field = observerWrapperClazz.getDeclaredField("mLastVersion")
mLastVersionField.isAccessible = true
val mVersionField: Field = liveDataClazz.getDeclaredField("mVersion")
mVersionField.isAccessible = true
val mVersionValue: Any = mVersionField.get(this)!!
mLastVersionField.set(boundObserver, mVersionValue)
}.onFailure {
it.printStackTrace()
}
}
}
}