1. LiveData 简介
LiveData 是一种具有生命周期感知能力的可观察数据持有类;LiveData 可以保证屏幕上的显示内容和数据一直保持同步。
特点:
- LiveData了解 UI 界面的状态,如果 activity 不在屏幕上显示,LiveData 不会触发没必要的界面更新,如果 activity 已经被销毁,会自动清空与 observer 的连接,意外的调用就不会发生。
- LiveData 会自动在 DESTROYED 的状态下移除 Observer ,取消订阅,所以不用担心内存泄露;
- LiveData 跟 LifecycleOwner 绑定,能感知生命周期变化,并且只会在 LifecycleOwner 处于 Active 状态(STARTED/RESUMED)下通知数据改变;
LiveData 的生命周期感知是由 Lifecycle 来实现的;不了解Lifecycle的可以查看Android Jetpack - Lifecycle 组件使用及解析
2. LiveData 使用方法
- 项目中 LiveData 一般都存放在ViewModel 中,以保证 app 配置变更时,数据不会丢失;在 ViewModel 创建具体的 LiveData 实例来存储数据,如下:
public class NameViewModel extends ViewModel {
private MutableLiveData<String> currentName;
public MutableLiveData<String> getCurrentName() {
if (currentName == null) {
currentName = new MutableLiveData<>();
}
return currentName;
}
}
定义一个 MutableLiveData
(LiveData 的一个常用子类),通过 observe
方法可以订阅修改数据的通知,通过 postValue()
或者 setValue()
方法可以更新数据,已经订阅的 Observer 能够得到数据更改的通知,也即回调 onChanged()
方法。
- 使用 LiveData 对象的 observe 或 observeForever 方法将对应的 Activity 或 Fragment 等添加为该 LiveData 对象的观察者,如下:
//需要一个观察者来观察数据
Observer<String> observer = new Observer<String>() {
@Override public void onChanged(String s) {
nameTextView.setText(s);
}
};
//获取到 viewmodel
NameViewModel model = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(this.getApplication())).get(NameViewModel.class);
// 取出 LiveData 完成订阅
model.getCurrentName().observe(this, observer);
// observeForever:无论何时,只要数据发生改变,就会触发 observer.onChanged()
// model.getCurrentName().observeForever(observer);
- 使用 LiveData 的 setValue 或 postValue 更新数据,然后在观察者,也就是 Activity 或 Fragment 中就获取更新数据了,如下:
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String anotherName = "name" + (i++);
// LiveData 发送消息通知 observer 更新数据
model.getCurrentName().setValue(anotherName);
}
});
注意:
setValue 只能在主线程运行
postValue 只能在子线程中运行
3. LiveData 核心原理
3.1 LiveData.observe()
LiveData 的使用流程从 observe() 开始
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
// 检查是否为ui线程
assertMainThread("observe");
//如当前UI的状态的是 DESTROYED 则忽略
if (owner.getLifecycle().getCurrentState() == DESTROYED) {// 1
// ignore
return;
}
//把 Observer 用 LifecycleBoundObserver 包装起来
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);// 2
//缓存起来
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);// 3
//如果已经 observe 过 并且两次的 owner 不同则报错
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
// 把 wrapper 与 Activity/Fragment 的生命周期,建立关系,
// 当 UI 的生命周期发生变化的时候,就会去回调 wrapper 中的 onStateChanged
owner.getLifecycle().addObserver(wrapper);// 4
}
注释1处的 owner 实际上就是注册时传进来来组件,比如 Activity,获取组件当前的状态,如果状态为 DESTROYED,那么直接 return,这说明 DESTROYED 状态的组件是不允许注册的。
注释2处新建了一个 LifecycleBoundObserver 包装类,将 owner 和 observer 传了进去。
可以看到 observe 方法里把我们传递的 observer 用 LifecycleBoundObserver 包装了起来,并且存入了 mObservers ,并且跟 owner 进行了关联。
注释3处将 observer 和 LifecycleBoundObserver 存储到SafeIterableMap<Observer<? super T>, ObserverWrapper>mObservers
中,putIfAbsent 方法和 put 方法有区别,如果传入 key 对应的 value 已经存在,就返回存在的 value,不进行替换。如果不存在,就添加 key 和 value,返回null。
如果等于 null,在注释4处会将 LifecycleBoundObserver 添加到 Lifecycle 中完成注册,这样当我们调用 LiveData 的 observe 方法时,实际上是 LiveData 内部完成了 Lifecycle 的观察者的添加,这样 LiveData 自然也就有了观察组件生命周期变化的能力。
两个特殊处理:
- 忽视处于 DESTROYED 的 owner 的注册行为;
- 将一个 Observer 同时绑定两个 LifecycleOwner 的行为视为非法操作,也即一个 Observer 只能绑定一个 owner,而 owner 可以有多个 Observer;
3.2 LifecycleBoundObserver
LifecycleBoundObservers 是 LiveData 的内部类,代码如下所示:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
// 判断 owner 当前的状态是否是至少 STARTED
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
// 当生命周期发生变化时,会调用这个函数
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
// 当UI的生命周期为DESTROYED,取消对数据变化的监听,移除回调函数
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
// 改变数据,传递的参数是shouldBeActive(),它会计算看当前的状态是否是STARTED,也就是 onStart-onPause 期间生命周期
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
// 是否是 active 状态
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
void activeStateChanged(boolean newActive) {
// 当前的生命周期和上一次的生命周期状态,是否发生变化,没有发生变化,就直接返回。
// onStart-onPause 为 true 在这之外的生命周期为false
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
// 这是一个空函数,可在代码中根据需要进行重写
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
// 这是一个空函数,可在代码中根据需要进行重写
onInactive();
}
// 如果 active 状态下,则发送数据更新通知
if (mActive) {
dispatchingValue(this);// 1
}
}
}
LifecycleBoundObserver 是 抽象类 ObserverWrapper 的子类,重写了 shouldBeActive() 方法,在 owner 处于至少是 STARTED 的状态下认为是 Active 状态,Active 状态包括 STARTED 和 RESUMED 状态。
LifecycleBoundObserver 实现了 GenericLifecycleObserver 接口,可以监听 lifecycle 回调,并且在 onStateChanged() 方法里处理了生命周期改变的事件,当接收到 DESTROYED 的事件会自动解除跟 owner 的绑定,并且将下个流程交给了 activeStateChanged() 。
这就是为什么一个观察者(组件)处于DESTROYED状态时,它将不会收到通知的原因。
问题一:LiveData 是如何跟 LifecycleOwner 进行绑定,做到感知生命周期的?
LiveData 在 observe 方法中用 LifecycleBoundObserver 包装了 observer ,并且通过它绑定了LifecycleOwner。
问题二:LiveData 只在 LifecycleOwner active 状态发送通知,是怎么处理的?
LifecycleBoundObserver 在 onStateChanged() 方法里处理了生命周期改变的事件,当接收到 DESTROYED 的事件会自动解除跟 owner 的绑定。
注意:当我们调用 observe() 注册后,由于绑定了 LifecycleOwner,所以在 active 的情况下,LiveData 如果有数据,则 Observer 会立马接受到该数据修改的通知。
此时的流程是:
observe–>
onStateChanged–>
activeStateChanged–>
dispatchingValue–>
considerNotify–>
onChanged
可以称之为生命周期改变触发的流程,另外还有一种流程是 postValue&setValue 触发的流程,共两种。
3.2 activeStateChanged(boolean)
activeStateChanged 方法定义在抽象类 ObserverWrapper 中,它是 Observer 的包装类,activeStateChanged 方法会根据 Active 状态和处于 Active 状态的组件的数量,来对 onActive 方法和 onInactive 方法回调,这两个方法用于拓展LiveData 对象。注释1处,如果是 Active 状态,会调用 dispatchingValue
方法,并将自身传进去。
3.3 dispatchingValue(ObserverWrapper) 分析
void dispatchingValue(@Nullable ObserverWrapper initiator) {
//正在处于分发状态中
if (mDispatchingValue) {
//标记分发失效
mDispatchInvalidated = true;// 1
return;
}
//标记分发开始,
//进入while 循环前,设置为true,如果此时另外一个数据发生变化,到了此函数中就直接在上面返回了
mDispatchingValue = true;
do {
// 分发有效
// 开始for循环前,设置为false,for循环完,也会退出while循环
mDispatchInvalidated = false;
// 生命周期改变调用的方法 initiator 不为 null
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
// postValue/setValue 方法调用 传递的 initiator 为 null
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
// 这里mDispatchInvalidated 为true,表示在while循环未结束的时候,有其他数据发生变化,并调用了该函数
// 在上面的 if 判断中设置了 mDispatchInvalidated = true,
// 结束本次for循环,没有退出while循环,开始下一次for循环
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
// 标记不处于分发状态
mDispatchingValue = false;
}
considerNotify(ObserverWrapper)
方法:
private void considerNotify(ObserverWrapper observer) {
// 检查状态 确保不会分发给 inactive 的 observer
// 如果 ObserverWrapper 的 mActive 值不为 true,就直接 return
if (!observer.mActive) {
return;
}
// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
//
// we still first check observer.active to keep it as the entrance for events. So even if
// the observer moved to an active state, if we've not received that event, we better not
// notify for a more predictable notification order.
if (!observer.shouldBeActive()) {
// 如果当前observer对应组件的状态不是Active,就会再次调用activeStateChanged方法,并传入false,
// 其方法内部会再次判断是否执行onActive方法和onInactive方法回调
observer.activeStateChanged(false);
return;
}
// setValue 会增加 version ,初始 version 为-1
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//如果判断条件都满足会调用Observer的onChanged方法,这个方法正是使用LiveData的observe方法的回调。
observer.mObserver.onChanged((T) mData);
}
可以看到 dispatchingValue
正是分发事件逻辑的处理方法,而 considerNotify 方法则确保了只将最新的数据分发给 active 状态下的 Observer 。
可以看到 LiveData 引入了版本管理来管理数据 (mData)以确保发送的数据总是最新的。
dispatchingValue
这里分两种情况:
- ObserverWrapper 不为 null
- ObserverWrapper 为 null
3.3.1 ObserverWrapper 不为 null 的情况
LifecycleBoundObserver.onStateChanged 方法里调用了 activeStateChanged ,而该方法调用 dispatchingValue(this); 传入了 this ,也就是 LifecycleBoundObserver ,这时候不为 null 。
也就是说生命周期改变触发的流程就是这种情况,这种情况下,只会通知跟该 Owner 绑定的 Observer。
3.3.2 ObserverWrapper 为 null 的情况
除了生命周期改变触发的流程外,还有 postValue&setValue 流程,来看下这俩方法。
@MainThread // 说明setValue方法是运行在主线程中
protected void setValue(T value) {
// 必须在主线程调用 否则会 crash
assertMainThread("setValue");
// mVersion 表示数据发生了变化
mVersion++;// 增加版本号
// 保存了这次变化的数据
mData = value;
// 分发数据变化,调用回调函数
dispatchingValue(null); // 传入了 null
}
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
// 调用 setValue
setValue((T) newValue);
}
};
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
// 上一个 post 后还没有执行的 runnable,所以就不需要再 post 了,
// 但是注意,上面的 mPendingData 数据已经是新数据了
//用官方的话,就是 If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.
return;
}
// postValue 可以从后台线程调用,因为它会在主线程中执行任务
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
LiveData 的 postValue 方法其实就是把操作 post 到主线程,最后调用的还是 setValue 方法,注意 setValue 必须是在主线程调用。
setValue 方法调用了 dispatchingValue 方法,并传入了 null ,这个时候的流程则会通知 active 的 mObservers。
可以看到无论是 LiveData 的 observe 方法还是 LiveData 的 postValue/setValue 方法都会调用 dispatchingValue 方法。
LiveData 的两个流程都会走到 dispatchingValue 处理分发通知逻辑,并且在分发通知前会判断 owner 的状态,再加上 LiveData 本身内部的版本管理,确保了只会发送最新的数据给 active 状态下的 Observer。
注意:LiveData 对同时多次修改数据做了处理,如果同时多次修改,只会修改为最新的数据。
4. LiveData 其它关联类及知识点
4.1 Sticky Event
LiveData 被订阅时,如果之前已经更改过数据,并且当前 owner 为 active 的状态,activeStateChanged() 会被调用,也即会立马通知到 Observer ,这样其实就类似 EventBus 的 sticky event 的功能,但很多时候我们并不需要该功能。
4.2 AlwaysActiveObserver
默认情况下,LiveData 会跟 LifecycleOwner 绑定,只在 active 状态下更新,如若想要不管在什么状态下都能接收到数据的更改通知的话,怎么办?这时候需要使用 AlwaysActiveObserver
,改调用 observe 方法为调用 LiveData.observeForever(Observer) 方法即可。
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
wrapper.activeStateChanged(true);
}
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
return true;
}
}
4.3 MediatorLiveData
LiveData 还有一个子类是 MediatorLiveData,它允许我们合并多个 LiveData,任何一个 LiveData 有更新就会发送通知。比如我们的数据来源有两个,一个数据库一个网络,这时候我们会有两个 DataSource,也就是两个 LiveData,这个时候我们可以使用 MediatorLiveData 来 merge 这两个 LiveData。
示例一:
例如有一个需求:希望在ExitText中输入文字的同时,显示文字个数。
class MainViewModel : ViewModel() {
val message: MutableLiveData<String> = MutableLiveData()
val count: MediatorLiveData<Int> = MediatorLiveData()
init {
count.value = 0
count.addSource(message) {
val cnt = message.value?.length ?: 0
count.postValue(cnt)
}
}
fun postMessage(message: String) {
this.message.postValue(message)
}
}
EditText 的回调里通过 postMessage 更新 message,count 通过 addSource 监听 message 的变化后更新自己。
addSource
可以保证被监视 Livedata 不会被重复订阅,如果我们手动 observe 的话,可能会因为重复订阅造成数据接受异常,通过addSrouce的源码可以清楚看到这一点
@MainThread
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
Source<S> e = new Source<>(source, onChanged);
Source<?> existing = mSources.putIfAbsent(source, e);
if (existing != null && existing.mObserver != onChanged) {
throw new IllegalArgumentException(
"This source was already added with the different observer");
}
if (existing != null) {
return;
}
if (hasActiveObservers()) {
e.plug();
}
}
示例二:
class SecondViewModel : ViewModel() {
var data1: MutableLiveData<UserInfo> = MutableLiveData()
var data2: MutableLiveData<UserInfo> = MutableLiveData()
var mediatorLiveData: MediatorLiveData<UserInfo> = MediatorLiveData()
val user1 = UserInfo("李四1", (1000..5000).random())
val user2 = UserInfo("李四2", (1000..5000).random())
data1.postValue(user1)
data2.postValue(user2)
mediatorLiveData.addSource(data1, object : Observer<UserInfo> {
override fun onChanged(info: UserInfo) {
mediatorLiveData.value = info
}
})
mediatorLiveData.addSource(data2, object : Observer<UserInfo> {
override fun onChanged(info: UserInfo) {
mediatorLiveData.value = info
}
})
}
个我们定义了两个 MutableLiveData 表示正常的数据获取。MediatorLiveData
通过 addSource 方法将 data1 和 data2 合并一起组成新的 LiveData。onChanged 回调表示的是当 data1 和 data2 数据源数据发送变化的时候进行回调。通知界面UI进行数据刷新。
我们在Activity中使用:
secondViewModel.mediatorLiveData.observe(this, Observer {
if (it.name.contains("1")) {
mTvShow.text = "姓名:${it.name} \n薪水:${it.salary}"
} else {
mTvShowOther.text = "姓名:${it.name} \n薪水:${it.salary}"
}
})
4.4 Transformations
Transformations 允许我们把一个 LiveData 进行处理,变化成另外一个 LiveData,目前支持 map 跟 switchMap 两个方法,跟 RxJava 的操作类似。
比如,用 map 把一个 String 类型的 LiveData 转换成 Integer 类型:
Transformations.map(liveString, new Function<String, Integer>() {
@Override
public Integer apply(final String input) {
return Integer.valueOf(input);
}
}).observe(this, new Observer<Integer>() {
@Override
public void onChanged(@Nullable final Integer integer) {
}
});
4.4 LiveDataBus
EventBus 基于观察者模式,LiveData 也是,所以 LiveData 可以被用来做成 LiveDataBus。
基于 LiveData 封装 LiveDataBus 消息总线
5. 知识点梳理和汇总
- LiveData 的实现基于观察者模式(reactive patterns);
- LiveData 跟 LifecycleOwner 绑定,能感知生命周期变化,并且只会在 LifecycleOwner 处于 Active 状态(STARTED/RESUMED)下通知数据改变;如果数据改变发生在非 active 状态,数据会变化,但是不发送通知,等 owner 回到 active 的状态下,再发送通知;
- 如果想要一直收到通知,则需要用
observeForever()
方法; - LiveData 会自动在 DESTROYED 的状态下移除 Observer ,取消订阅,所以不用担心内存泄露;
- 在 LifecycleOwner 处于 DESTROYED 的状态下,不能订阅;
- postValue 方法其实最后调用了 setValue 只不过把操作放到主线程,适合在异步线程里调用,setValue 必须在主线程里调用;
- 如果同时多次调用 postValue 或 setValue 修改数据,只会修改成最新的那个数据,也即只会收到一次通知(set post混合调用则不一定);
- 如果 LiveData 有数据,并且 owner 在 active 状态下,那么在订阅的时候,会立马收到一次通知;
- 一个 Observer 实例,只能绑定一个 LifecycleOwner,而一个 owner 可以绑定多个 Observer 实例;
- LiveData 利用版本管理、绑定 Lifecycle 确保了只会发送最新的数据给 active 状态下的 Observer;