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

相关推荐
每次的天空2 小时前
Android第二次面试总结(项目拷打实战)
android
&有梦想的咸鱼&2 小时前
Android Dagger2 框架辅助工具模块深度剖析(六)
android
tangweiguo030519872 小时前
Android 全屏6位密码输入框:优化布局与功能实现
android·nginx
二流小码农4 小时前
鸿蒙开发:权限管理之授权方式
android·ios·harmonyos
每次的天空4 小时前
kotlin中的行为组件
android·开发语言·kotlin
wangz764 小时前
Kotlin,jetpack compose,Android,MPAndroidChart,折线图示例
android·kotlin·mpandroidchart
二流小码农4 小时前
鸿蒙开发:申请授权权限
android·ios·harmonyos
锋风5 小时前
音视频缓存数学模型
android
_一条咸鱼_5 小时前
深入剖析 Android Dagger 2 框架的注解模块(一)
android