概述
LiveData是一个可以在给定生命周期内观察到的数据持有者类。一个观察者可以与一个LifecycleOwner成对地添加,并且只有当配对的LifecycleOwner处于活动状态时,这个观察者才会收到数据变动的通知。
使用
//使用方式很简单,最核心的两点就是注册,发送和接收,可以理解为带生命周期监听的EventBus
//注册 owner表示具有生命周期的Activity或者Fragment,observer是一个接口,用来处理回传的数据
LiveData.observe(LifecycleOwner owner,Observer super T> observer)
//发送 两者的差别很简单,postValue会先切换到主线程,然后再调用setValue
LiveData.postValue(T value)
LiveData.setValue(T value)
开始分析之前的知识点补充
jetpack
组件中对生命周期的监听,主要用到了Lifecycle
这个类.
这个类型有个枚举类Event
,
//各个属性都对应Activity下的各种生命周期
public enum Event {
ON_CREATE,
ON_START,
ON_RESUME,
ON_PAUSE,
ON_STOP,
ON_DESTROY,
ON_ANY
}
原理解析
1.从LiveData.observe()开始
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
//1.生命周期销毁,无法注册
return;
}
//2.LifecycleBoundObserver是一个包装类,对owner和observer进行了一次包装,用于监听
// 生命周期的变化,以及生命周期变化之后对observer的处理
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
//TAG-1
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
//3.进行注册
owner.getLifecycle().addObserver(wrapper);
}
标记处 TAG-1处会抛出一个异常,出现这个异常的原因通常是同一个observer关联了不同的LifecycleOwner导致的。
网上也有人说在使用 Lambda表达式中未使用非静态方法或引用 会出现这个问题,个人测试了下并不会出现这样的问题,因为在 existing.isAttachedTo(owner)
中会判断,owner
是否是相同的。
如果在Activity
和Fragment
中使用了声明成单例的 LiveData
是有可能出现这种错误的。
2.注册成功之后,来看虚假的信息发送者 postValue()
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
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);
}
};
1.postValue是异步线程操作,所以需要加上线程锁
2.mPendingData作为一个临时变量,用来存放post过来的value,同时起到减少锁范围内代码量的作用?
3.postValue最后还是执行到 setValue函数,所以最终的消息发送还是看setValue
这里有一个疑问
//这代代码为什么不这么写呢?如果有知道的问题能解答一下就好了。
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
}
3.来看真实的信息发送者 setValue()
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
//临时变量,用来保存value
mData = value;
dispatchingValue(null);
}
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;
}
1.dispatchingValue(null) 这里参数为null,表示需要遍历map,给对应的Observer发送消息
2.最终触发点在considerNotify()函数
4.看具体的considerNotify()函数
private void considerNotify(ObserverWrapper observer) {
//如果观察者当前处于不活跃状态,则不做信息分发,有两种情况观察者处于不活跃状态
//1.observer被remove掉,
//2.observer的生命周期在STARTED及之后,对应Activity的生命周期,onStart之后,onStop之前
if (!observer.mActive) {
return;
}
//在这里会对observer的生命周期进行一次检查
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//最后消息从这里发出
observer.mObserver.onChanged((T) mData);
}
LiveData存在的一些问题
数据倒灌,即先发送事件,再注册也能收得到数据
既然是注册之后,还能收到数据,这说明在注册的过程中触发到了onChanged()函数
1.我们再回到LiveData.observe()
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
...
//这次只需要看这一步就可以了,具体的实现位置在LifecycleRegistry的addObserver函数
owner.getLifecycle().addObserver(wrapper);
}
//LifecycleRegistry.addObserver()
//看源代码的时候,跟着传入的参数看代码主结构,能快速的了解逻辑
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
//避免重复注册监听
if (previous != null) {
return;
}
...
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
pushParentState(statefulObserver.mState);
statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
popParentState();
targetState = calculateTargetState(observer);
}
...
}
1.根据observer创建了一个跟生命周期绑定的statefulObserver
2.通过statefulObserver.dispatchEvent()将生命周期事件发送出去。
2.进入ObserverWithState
static class ObserverWithState {
State mState;
LifecycleEventObserver mLifecycleObserver;
ObserverWithState(LifecycleObserver observer, State initialState) {
//通过Lifecycling创建一个LifecycleObserver,具体的实现类为LifecycleBoundObserver,
mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
mState = initialState;
}
void dispatchEvent(LifecycleOwner owner, Event event) {
State newState = getStateAfter(event);
mState = min(mState, newState);
//这一段是当生命周期状态变化时触发的,具体的处理类为LifecycleBoundObserver
mLifecycleObserver.onStateChanged(owner, event);
mState = newState;
}
}
3.进入LifecycleBoundObserver.onStateChanged()
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//如果页面销毁,则remove监听者,这也是为什么不需要手动回收监听者的原因
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//如果界面处于活跃状态,onStart,onResmue,onPasue 这几个状态都属于活跃状态
activeStateChanged(shouldBeActive());
}
void activeStateChanged(boolean newActive) {
//状态相同,则不做处理
if (newActive == mActive) {
return;
}
...
//活跃状态下进行value分发
if (mActive) {
dispatchingValue(this);
}
}
4.最后还是回到了LiveData.dispatchingValue()
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
//只不过这一次是进入到这个case中,来对事件进行发送的
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;
}
5.LiveData的considerNotify()
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//这次主要看这里
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
1.mLastVersion是ObserverWrapper的一个version,默认值为-1,每次new ObserverWrapper都会重置
2.mVersion是LiveData的version,默认也为1,每次setValue的时候会+1
如果一个LiveData,先setValue导致mVersion+1,之后在注册监听,就会出现
observer.mLastVersion==-1,mVersion==1的情况,使得数据倒灌。
看到这里产生一个疑问
//这个判断是起到什么作用的呢?为了拦截多线程操作时候产生的信息多次发生的问题吗?
if (observer.mLastVersion >= mVersion) {
return;
}
数据倒灌的解决方案
第一种方案,自定义LiveData,增加粘性事件的处理逻辑
class BaseLiveData : MutableLiveData() {
fun observe(owner: LifecycleOwner, observer: Observer, isSticky: Boolean = false) {
if (!isSticky) {
super.observe(owner, observer)
} else {
super.observe(owner, CustomObserver(observer))
}
}
class CustomObserver(val observer: Observer) : Observer {
override fun onChanged(t: T) {
//数据倒灌,在这里增加拦截逻辑
// observer.onChanged(t)
}
}
}
1.增加一个参数isSticky,表示可能会发送数据倒灌,然后自己在CustomObserver增加处理逻辑
缺点:用起来不够只能,而且有可能跟业务耦合
第二种方案,通过hook修改version的值
class UnPeekLiveData : MutableLiveData() {
override fun observe(
owner: LifecycleOwner,
observer: Observer
) {
super.observe(owner, observer)
hook(observer)
}
private fun hook(observer: Observer) {
val liveDataClass = LiveData::class.java
try {
//获取field private SafeIterableMap, ObserverWrapper> mObservers
val mObservers = liveDataClass.getDeclaredField("mObservers")
mObservers.isAccessible = true
//获取SafeIterableMap集合mObservers
val observers = mObservers[this]
val observersClass: Class<*> = observers.javaClass
//获取SafeIterableMap的get(Object obj)方法
val methodGet =
observersClass.getDeclaredMethod("get", Any::class.java)
methodGet.isAccessible = true
//获取到observer在集合中对应的ObserverWrapper对象
val objectWrapperEntry = methodGet.invoke(observers, observer)
var objectWrapper: Any? = null
if (objectWrapperEntry is Map.Entry<*, *>) {
objectWrapper = objectWrapperEntry.value
}
if (objectWrapper == null) {
throw NullPointerException("ObserverWrapper can not be null")
}
//获取ObserverWrapper的Class对象 LifecycleBoundObserver extends ObserverWrapper
val wrapperClass: Class<*>? = objectWrapper.javaClass.superclass
//获取ObserverWrapper的field mLastVersion
val mLastVersion =
wrapperClass!!.getDeclaredField("mLastVersion")
mLastVersion.isAccessible = true
//获取liveData的field mVersion
val mVersion = liveDataClass.getDeclaredField("mVersion")
mVersion.isAccessible = true
val mV = mVersion[this]
//把当前ListData的mVersion赋值给 ObserverWrapper的field mLastVersion
mLastVersion[objectWrapper] = mV
mObservers.isAccessible = false
methodGet.isAccessible = false
mLastVersion.isAccessible = false
mVersion.isAccessible = false
} catch (e: Exception) {
e.printStackTrace()
}
}
}
核心思想就是在observe
的时候,将mLastVersion
和mVersion
的值同步。
缺点:这种方式侵入式比较强,如果官方修改了源码,这里就需要跟着修改
第三种方案:通过MediatorLiveData处理
数据倒灌的原因是先发送信息,后注册,这个时候还能收到之前发送的消息,那么我们可以
将在注册之前发送的消息置为无效就可以了。
open class BaseLiveData {
private val source = MediatorLiveData>()
open fun post(event: T) = runOnUI {
val eventWrapper = EventWrapper(event)
//step 1
source.value = eventWrapper
//step 2
eventWrapper.hasBeenHandled = true
}
fun observe(lifecycleOwner: LifecycleOwner, observer: Observer) {
val mediator = createUnwrapMediator()
mediator.observe(lifecycleOwner, observer)
}
/**
* 获取上一次事件缓存值,可能为空
*/
fun peekEvent(): T? {
return source.value?.peekContent()
}
/**
* 新建一个中间层. 用来筛掉那些已经被处理过的事件. 其实相当于注册一个 forever 的 observer
*/
private fun createUnwrapMediator(): MediatorLiveData {
val mediator = MediatorLiveData()
mediator.addSource(source) { event ->
//step 3
if (!event.hasBeenHandled) {
mediator.value = event.peekContent()
}
}
return mediator
}
}
class MutablePublishData : BaseLiveData() {
public override fun post(event: T) {
super.post(event)
}
}
open class EventWrapper(private val content: T) {
var hasBeenHandled = false
internal set
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
content
}
}
fun peekContent(): T = content
}
val uiHandler by lazy {
Handler(Looper.getMainLooper())
}
fun runOnUI(action: () -> Unit) {
if (Looper.getMainLooper() == Looper.myLooper()) {
action.invoke()
} else {
uiHandler.post(action)
}
}
fun runOnUIDelay(delay: Long, action: () -> Unit) {
uiHandler.postDelayed(action, delay)
}
这部分代码主要看几个部分
source
是原始数据源,每次post数据的时候都会给它赋值createUnwrapMediator()
这里返回的是具体监听者,监听的是source
这个数据源,随着source
数据更新而产生回调。回头看
step1
标记的地方,如果这个时候没有注册监听者,会将hasBeenHandled
标记为true,表示事件已经消费掉,也就不会产生数据倒灌的问题如果
post()
信息的时候,已经有注册者了,这个时候的调用顺序为 step1->step3->step2。会先将事件发送出去,再修改hasBeenHandled
的值。
补充的小知识点
- lambda表达式如果未持有外部类对象,那么kotlin编译器会进行单例优化。
- Jetpack介绍之MediatorLiveData