一、认识LiveData
LiveData是Google JetPack组件中的生命周期感应组件,自带生命周期管理。它可以很方便地帮我们管理MVVM模式中界面数据的自动化更新。我们可以理解LiveData是一个具有生命周期自感应的数据容器,也是LiveData的核心特色。
二、LiveData的使用
LiveData的使用一般配合ViewModel使用。在ViewModel中定义LiveData值,在Activity中订阅。
2.1 基础使用
- 如实例所示,在ViewModel中定义LiveData,一般定义LiveData时会定义一个对内可修改的私有属性,对外提供一个只读的公开属性,只读LiveData指向内部可写LiveData,在UI层(例子中是MainActivity)订阅公开的只读的LiveData,如此将每次ViewModel的内部的LiveData值的变更都能传递到UI层通过公开LiveData订阅的观察者。
MainViewModel
class MainViewModel: ViewModel() {
/**
* 数1
*/
private val _numOneLiveData = MutableLiveData<Int>()
val numOneLiveData: LiveData<Int> = _numOneLiveData
/**
* 数2
*/
private val _numTwoLiveData = MutableLiveData<Int>()
val numTwoLiveData: LiveData<Int> = _numTwoLiveData
...
}
MainActivity
class MainActivity : ComponentActivity() {
private val viewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
observeLiveData()
}
private fun observeLiveData() {
// 观测数1
viewModel.numOneLiveData.observe(this) {
it.toString()
}
// 观测数2
viewModel.numTwoLiveData.observe(this) {
it.toString()
}
}
}
2.2 进阶使用
- 场景一:在2.1的例子中,每个LiveData都对应一个独立的观测场景。我们更近一步的需求是,在UI层不仅需要观测numOne和numTwo的值,还希望显示两个数的和,且要观测两数之和。这种情况下,可以通过使用
MediatorLiveData
来实现该功能:定义一个MediatorLiveData类型的result,通过给result添加source,则可以在source对象发生变更时及时通知到result对象,从而完成其他值的变更监听,响应变化。
MainViewModel
class MainViewModel: ViewModel() {
...
init {
_result.addSource(numOneLiveData) {
val one = it?:return@addSource
val two = numTwoLiveData.value?:return@addSource
_result.value = two + one
}
_result.addSource(numTwoLiveData) {
val one = numOneLiveData.value?:return@addSource
val two = it?:return@addSource
_result.value = two + one
}
}
fun inc(type: Type) {
when (type) {
is Type.One -> {
_numOneLiveData.value = (_numTwoLiveData.value?:0) + 1
}
is Type.Two -> {
_numTwoLiveData.value = (_numTwoLiveData.value?:0) + 1
}
}
}
fun des(type: Type) {
when (type) {
is Type.One -> {
_numOneLiveData.value = (_numOneLiveData.value?:0) + 1
}
is Type.Two -> {
_numTwoLiveData.value = (_numTwoLiveData.value?:0) + 1
}
}
}
}
三、LiveData的使用注意事项
3.1 关于订阅LiveData
- 对LiveData对象使用
observe(LifecycleOwner, Observer<? super T>)
注册监听时,无需手动解除监听,无需担忧内存泄漏问题。
LiveData对象会对注册进来的observer根据LifecycleOwner进行管理,在onStop阶段进入非活跃状态,在destroy状态解除绑定。
- 对LiveData对象使用
observeForever(Observer<? super T>)
注册监听时,与生命周期无绑定关系,需手动解除监听,否则可能存在内存泄漏的隐患。
使用这个函数注册的观察者会一直处于活跃状态。对所有的观察者实时分发变更。具体源码解析部分可以往下看,观察者在传递到内部实际会被转化为
AlwaysActiveObserver
对象。
- 当调用LiveData的observe方法时,若此时LiveData有值,订阅者符合活跃状态的判定,则LiveData的机制是会立即回调当前值。若需要修改这里的机制,可以通过继承LiveData自行实现。
- 对于LiveData监听的主动解除函数调用,需要保证在主线程中调用,使用时需要特别注意。
LiveData
@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner) {
assertMainThread("removeObservers");
...
}
@MainThread public void removeObserver(@NonNull final Observer<?super T> observer) {
assertMainThread("removeObserver");
...
}
3.2 关于LiveData写值
LiveData#setValue(T)
只可在主线程调用,子线程调用会抛出异常。
setValue(T)
的更新值方式是直接更新,除了更新值本身,也会更新一个mVersion
字段来标记当前值的版本,setValue(T)
函数也对主线程做了注解标记@MainThread
,同时函数内也做了断言判断,所以如果在子线程调用会抛出异常。
LiveData#postValue(T)
是子线程更新LiveData的方案。post出来的数据若消费不及时,可能发生数据未被消费就被覆盖的情况的,从而出现数据丢失的情况。
postValue(T)
的实现原理是通过使用mPendingData来保存post的数据,mPendingData的数据会在内部post出去的runnable内部类的实例中被消费,若mPendingData数据被消费,则值会被重置为NOT_SET
。若mPendingData未被消费时,外部调用postValue函数只会修改mPendingData的值,等待未被执行的runnable执行时被消费。
LiveData
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
setValue(T)
和postValue(T)
混用注意事项。
在
postValue(T)
的函数源码中,官方的注释说明中明确提醒,当先调用postValue(T)
再调用setValue(T)
,最后生效的值会是postValue(T)
写入的值,所以当一个公开的LiveData数据,需要注意修改者的调用方式和调用顺序,避免出现不符合预期的结果。
四、深入理解LiveData的工作机制
4.1 关于LiveData本身
LiveData是一个抽象类,无法被实例化。其派生出来的公开的可直接使用的子类包括:
MutableLiveData
和MediatorLiveData
。MutableLiveData
提供了可读可写的能力,而MediatorLiveData
提供了LiveData监听LiveData的能力,提供了LiveData更多的组合灵活性。还有一些系统内部自己实现的LiveData内部的派生类:CoroutineLiveData
、LoaderManagerImpl.LoaderInfo
、SavedStateHandle.SavingStateLiveData
,系统应用于特定的业务场景,感兴趣的同学可以深入源码再细读。
- LiveData的构造函数默认支持两种:带初始值和不带初始值。
- 关于值的设置:LiveData中用来记录具体数值的mData对象会被设置为NOT_SET值,NOT_SET是LiveData用来标记是否无值状态的对象,同样它也被用在postValue函数用来标记mPendingData对象,从而实现一些逻辑控制。
- 关于值的版本:LiveData内部使用一个mVersion变量来标记mData值的版本,
LiveData
/**
* Creates a LiveData initialized with the given { @code value}.
*
* @param value initial value
*/
public LiveData(T value) {
mData = value;
// 一旦开始写值,版本号就会从默认值开始累积
mVersion = START_VERSION + 1; // static final int START_VERSION = -1;
}
/**
* Creates a LiveData with no value assigned to it.
*/
public LiveData() {
mData = NOT_SET;
mVersion = START_VERSION;
}
4.2 LiveData的线程安全问题
- LiveData写值的线程安全保障:
setValue(T)
与postValue(T)
。
LiveData的postValue是允许在子线程调用的,所以对mPendingData的写值需要做线程安全控制,mPendingData的写值使用了对象锁mDataLock来做访问控制。mData使用volatile
修饰来保证线程可见性。
LiveData
@SuppressWarnings("WeakerAccess") /* synthetic access */
volatile Object mPendingData = NOT_SET;
final Object mDataLock = new Object();
private volatile Object mData;
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
// 读写加锁
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
protected void postValue(T value) {
boolean postTask;
// 读写加锁
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
- LiveData订阅非线程安全:订阅者的管理使用的是非线程安全的容器,所以LiveData的observe和removeObserve函数都限定在主线程调用,同时函数有线程断言,若发现在非主线程中调用会立即抛出异常。
LiveData
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
...
}
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
...
}
@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
assertMainThread("removeObserver");
...
}
@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner) {
assertMainThread("removeObservers");
...
}
4.3 当我们调用obsserve函数发生了什么?
这里从常用的observe(LifecycleOwner, Observer)
函数分析。 从代码中可以发现,当LifcycleOwner
的状态在DESTROYED
状态时。observe调用为无效调用,会直接被忽略。接下来就是正常流程:
- 将owner和observer对象包装到
LifecycleBoundObserver
类型的wrapper对象中(LifecycleBoundObserver是LifecycleEventObserver
接口的实现类)- 在LiveData内部会有一个map来存储observer和wrapper的映射,不允许重复添加,否则抛出异常
- 给传入的owner的Lifecycle注册监听对象wrapper
LiveData
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
// 1. 对象二次包装
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 2. 是否重复添加判断
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
// 3.向owner订阅Lifecycle change事件
owner.getLifecycle().addObserver(wrapper);
}
我们知道observe调用的同时,若LiveData处于有值的状态时,observer会被立即回调,这部分的逻辑代码则实现在LifecycleBoundObserver
实现的LifecycleEventObserve
接口定义的onStateChange(LifecycleOwner, Lifecycle.Event)
函数中。 在该函数的实现中:
- 对DESTROYED过滤,对观察者进行移除
- 根据生命周期状态对外进行活跃状态的分发,
activeStateChanged(boolean)
的实现在其父类ObserverWrapper
中,它会根据mActive状态是否变更来决定是否分发value给observer
LifecycleBoundObserver
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
...
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
// 1. 对DESTROYED过滤
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
// 2. 根据生命周期状态对外进行活跃状态的分发
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
// 3. activeStateChanged的实现在父类ObserverWrapper中
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean shouldBeActive() {
// 根据当前的生命周期阶段进行判断
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
...
}
- 最终会调用到LiveData的dispatcherValue(ObserverWrapper)函数中的
considerNotify(ObserverWrapper)
函数。在该函数中:- 若当前为非活跃状态,则会将当前的不活跃状态更新到observer中,待下次再次出发lifecycle state change时,响应当页面转化为活跃状态后能收到数据变更回调;
- 若当前为活跃状态,则立即回调当前的observer的onChange函数发出的mData值。
LiveData
@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
...
do {
mDispatchInvalidated = false;
// 首次订阅走的是if成立的逻辑
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
...
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
@SuppressWarnings("unchecked")
private void considerNotify(ObserverWrapper observer) {
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);
}
4.4 LiveData如何根据LifecycleOwner的生命周期对订阅者进行管理?
这部分和订阅过程的分析有部分重叠,由4.3部分,我们可知在observer被调用onChange前需要对LifecycleOwner的Lifecycle State做对应的处理。 而当Lifecycle state为Destroy时,Observer需要解除绑定。解除绑定的行为在LifecycleBoundObserver
的onStateChange(LifecycleOwner, Lifecycle.Event)
中执行,由于LifecycleBoundObserver
是一个内部类,可直接访问LiveData的函数,通过调用LiveData的removeObserve(Observer)
解除LiveData的observer在LiveData队列中的引用,同时移除LifecycleOwner中的Lifecycle Change的监听。
LiveData
public abstract class LiveData<T> {
@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
assertMainThread("removeObserver");
ObserverWrapper removed = mObservers.remove(observer);
if (removed == null) {
return;
}
// 移除Lifecycle的observer
removed.detachObserver();
removed.activeStateChanged(false);
}
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
...
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
if (currentState == DESTROYED) {
// 移除观察者
removeObserver(mObserver);
return;
}
...
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
...
}
}