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循环,事件分发又开始重新执行了,再继续执行给第一次没收到消息的观察者发信息的逻辑中,但这时候的发送的消息也变成最新的了,之前发送过的人就不再发送了。

相关推荐
BD_Marathon5 小时前
【MySQL】函数
android·数据库·mysql
西西学代码5 小时前
安卓开发---耳机的按键设置的UI实例
android·ui
maki07710 小时前
虚幻版Pico大空间VR入门教程 05 —— 原点坐标和项目优化技巧整理
android·游戏引擎·vr·虚幻·pico·htc vive·大空间
千里马学框架10 小时前
音频焦点学习之AudioFocusRequest.Builder类剖析
android·面试·智能手机·车载系统·音视频·安卓framework开发·audio
fundroid14 小时前
掌握 Compose 性能优化三步法
android·android jetpack
TeleostNaCl14 小时前
如何在 IDEA 中使用 Proguard 自动混淆 Gradle 编译的Java 项目
android·java·经验分享·kotlin·gradle·intellij-idea
旷野说16 小时前
Android Studio Narwhal 3 特性
android·ide·android studio
maki0771 天前
VR大空间资料 01 —— 常用VR框架对比
android·ue5·游戏引擎·vr·虚幻·pico
xhBruce1 天前
InputReader与InputDispatcher关系 - android-15.0.0_r23
android·ims
领创工作室1 天前
安卓设备分区作用详解-测试机红米K40
android·java·linux