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

相关推荐
___波子 Pro Max.31 分钟前
Android envsetup与Python venv使用指南
android·python
武帝为此1 小时前
【MySQL 删除数据详解】
android·数据库·mysql
顾林海1 小时前
深度解析HashMap工作原理
android·java·面试
V少年2 小时前
深入浅出DiskLruCache原理
android
鱼洗竹2 小时前
协程的挂起与恢复
android
清风~徐~来3 小时前
【Linux】进程创建、进程终止、进程等待
android·linux·运维
百锦再3 小时前
Android游戏辅助工具开发详解
android·游戏·模拟·识别·辅助·外挂
QING6184 小时前
Kotlin 类型转换与超类 Any 详解
android·kotlin·app
QING6184 小时前
一文带你了解 Kotlin infix 函数的基本用法和使用场景
android·kotlin·app
张风捷特烈5 小时前
平面上的三维空间#04 | 万物之母 - 三角形
android·flutter·canvas