Jetpack源码解读(二)——LiveData

一、概述

本文主要讲解LiveData的源码,结合了具体的情境,需到先理解上一篇文章Lifecycle的源码,这里默认大家使用方法都是会的,就像下面这样:

typescript 复制代码
private val liveData: MutableLiveData<String> by lazy {
	MutableLiveData<String>()
}

liveData.observe(this){
	Log.d("MainActivity!", it)
}

liveData.value = "Hello World!"

二、添加观察者

LiveData 添加一个观察者用到的是observe 方法,看一下这个函数的样子:

less 复制代码
public abstract class LiveData<T> {
	private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
		new SafeIterableMap<>();
	
	@MainThread
	public void observe(@NonNull LifecycleOwner owner, 
						@NonNull Observer<? super T> observer) {
		//省略一些代码
		LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
		ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
		//省略一些代码
		owner.getLifecycle().addObserver(wrapper);
	}
}

这里出现了一个LifecycleBoundObserver,他将我们传入的LifecycleOwnerObserver封装在里面,然后再将他添加到Lifecycle的观察者中去。

LifecycleBoundObserver的构造函数中,调用了ObserverWrapper的构造函数:

less 复制代码
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
	super(observer);
	mOwner = owner;
}

而在ObserverWrapper中有个成员变量,将这个observer给保存了先来,接下来就会用到它。

kotlin 复制代码
private abstract class ObserverWrapper {
	final Observer<? super T> mObserver;
	ObserverWrapper(Observer<? super T> observer) {
		mObserver = observer;
	}
}

LiveData还将这个包装好的ObserverWrapper添加到自己的成员变量mObservers中去,这个显然就是存放 LiveData观察者的地方。

最后继续再将ObserverWrapper添加Lifecycle的观察者中去,使用这个LiveData既是一个观察者,它在观察宿主生命周期方法,又是一个被观察者,自己的数据被另一个观察者观察。

三、通知观察者

LiveData有两个设置数据的方法,也是通知观察者的方法,postValue是在非主线程中使用,而setValue是在主线程中使用。

scala 复制代码
public class MutableLiveData<T> extends LiveData<T> {
	@Override
	public void postValue(T value) {
		super.postValue(value);
	}

	@Override
	public void setValue(T value) {
		super.setValue(value);
	}
}
typescript 复制代码
@MainThread
protected void setValue(T value) {
	assertMainThread("setValue");
	mVersion++;
	mData = value;
	dispatchingValue(null);
}

setValue()主要做了三件事情。

  1. 将初始值为-1mVersion++
  2. 将存储最新成员变量的mData设置为当前的值
  3. dispatchingValue通知观察者

先主要看dispatchingValue方法:

ini 复制代码
private boolean mDispatchingValue;
private boolean mDispatchInvalidated;

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;
}

先不看细节,走入最主要的considerNotify()方法中去:

ini 复制代码
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);
}

最后看到了observer.mObserver.onChanged((T) mData)方法,调用了我们传入observer的方法,实现了消息的回调。

在这之前做了三个判断:

  1. 跳过非活跃观察者

验证一下各个观察者的生命周期情况。

  1. 动态验证 activity 活跃性

我们可以看到shouldBeActive方法返回的是mOwner也就是 activity是不是至少处在STARTED生命周期。这就保证了发消息的人是活跃的,收消息的人也是活跃的。

scss 复制代码
@Override
boolean shouldBeActive() {
	return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
  1. 版本控制

我们在上面也强调了mVersionmData这两个成员变量。仔细分析一下能得出一个结论:当观察者的最后版本号也就是mLastVersion在没有通过上面三个验证的时候是不会改变的,并且消息是不会发送的,就假设他前面几个消息没收到,在某一个情况下,突然上面三个验证又通过了,那他就只会保留发送的最会一次消息,也就是最新的消息,而且版本号也会被更新为最新的,中间跳过的就不要了。这到底有什么用呢,我分析完下一个特性再来讲解一下吧。

貌似LiveData的机制就这么点,其实这里面还是有很多细节在的,接下来我们逐一分析一下!

四、生命周期变化响应机制

前面我们分析了在 setvalue 的时候会触发状态改变的回调,但是他还会在另一个地方会被回调。

还记得前面包装类LifecycleBoundObserver吗?他被绑定成了 lifecycle 的观察者,在 activity 生命周期发生改变的时候就会触发它的onStateChanged回调。

less 复制代码
@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();
	}
}

在就去activeStateChanged方法:

ini 复制代码
void activeStateChanged(boolean newActive) {
	if (newActive == mActive) {
		return;
	}
	mActive = newActive;
	changeActiveCounter(mActive ? 1 : -1);
	if (mActive) {
		dispatchingValue(this);
	}
}

这里又走到了dispatchingValue和上面不一样的是这里传进去一个 this,上面传进去的是 null

less 复制代码
void dispatchingValue(@Nullable ObserverWrapper initiator) {
	//省略版
	if (initiator != null) {
		considerNotify(initiator);
	} else {
		for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
			 mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
			considerNotify(iterator.next().getValue())
		}
	}

}

最终还是会走到considerNotify中去。

这里回忆一下上面的版本控制,这边再模拟一种情况,当发送数据的状态是活跃的,接收消息的 activity 当前是不活跃的,无论你发了多少数据,最新的总会保留,并且在接受者 activity 状态变化时候,会重新回调considerNotify这个时候即使你先发的数据,观察者后来才活跃起来的,或者后来再加进去的,只要生命周期变化,就会收到最新的数据。这个就是粘性消息的机制。

五、dispatchingValue 强大的机制

回到上面说的dispatchingValue方法,我们把代码抄回来放在下面:

ini 复制代码
private boolean mDispatchingValue;
private boolean mDispatchInvalidated;

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;
}

这里出现了很多的mDispatchingValuemDispatchInvalidated,理解他的关键在于你在观察者观察到数据之后又发送数据,就像这么写:刚观察到就发送消息!

javascript 复制代码
liveData.observe(this){
	liveData.value = "Hello World!"
}

想象一下,又好多个观察者,在他们一个个轮流收到数据的时候,中间突然有个人发送了数据,这个时候的mDispatchingValueTrue,它会将mDispatchInvalidated也变成 True,这样接下来的这一轮发送都会走在 break 中,不会触发回调。而又因为这里有个 while循环,事件分发又开始重新执行了,再继续执行给第一次没收到消息的观察者发信息的逻辑中,但这时候的发送的消息也变成最新的了,之前发送过的人就不再发送了。

相关推荐
JhonKI4 小时前
【MySQL】存储引擎 - CSV详解
android·数据库·mysql
开开心心_Every5 小时前
手机隐私数据彻底删除工具:回收或弃用手机前防数据恢复
android·windows·python·搜索引擎·智能手机·pdf·音视频
大G哥5 小时前
Kotlin Lambda语法错误修复
android·java·开发语言·kotlin
鸿蒙布道师9 小时前
鸿蒙NEXT开发动画案例2
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
androidwork9 小时前
Kotlin Android工程Mock数据方法总结
android·开发语言·kotlin
xiangxiongfly91511 小时前
Android setContentView()源码分析
android·setcontentview
人间有清欢12 小时前
Android开发补充内容
android·okhttp·rxjava·retrofit·hilt·jetpack compose
人间有清欢13 小时前
Android开发报错解决
android
每次的天空14 小时前
Android学习总结之kotlin协程面试篇
android·学习·kotlin
每次的天空16 小时前
Android学习总结之Binder篇
android·学习·binder