1、概述
LiveData 是一种具有生命周期感知能力的可观察数据持有类,可以保证屏幕上的显示内容和数据一直保持同步。
特点:
- LiveData 是一个观察者。它可以感知宿主(Activity 或 Fragment)的生命周期。如果宿主不处于活动状态(屏幕上不可见),LiveData 不会触发没必要的界面更新,这样能避免空指针异常和不必要的性能损耗
- LiveData 也是一个被观察者。 如果宿主已经被销毁,LiveData 会自动清空与之连接的 Observer,从而避免内存泄漏
2、使用
2.1 基础使用
引入依赖:
def lifecycle_version = "2.4.0"
// Lifecycle only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
LiveData 一般会搭配 ViewModel 一起使用,被封装在 ViewModel 之中,以保证 app 配置变更时,数据不会丢失。首先定义 ViewModel,需持有一个 LiveData:
public class NameViewModel extends ViewModel {
// LiveData 内封装了 String 类型的数据
private MutableLiveData<String> name;
public MutableLiveData<String> getName() {
if (name == null) {
name = new MutableLiveData<>();
}
return name;
}
}
然后在 Activity 中生成 ViewModel 对象,并建立 ViewModel 内的 LiveData 的观察者与 Activity 之间的绑定关系:
public class NameActivity extends AppCompatActivity {
private NameViewModel nameViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_name);
final TextView textView = findViewById(R.id.text);
// 1.获取 NameViewModel 对象
nameViewModel = new ViewModelProvider(this).get(NameViewModel.class);
// 2.创建 LiveData 内数据的观察者
Observer<String> observer = new Observer<String>() {
@Override
public void onChanged(String string) {
// 当 LiveData 数据发生变化时,将变化后的字符串显示在 textView 上
textView.setText(string);
}
};
// 3.给观察者与 LifecycleOwner 建立绑定关系
nameViewModel.getName().observe(this, observer);
}
}
最后修改 LiveData 的内容,textView 显示的就是 LiveData 被修改后的内容了:
nameViewModel.getName().setValue("Count:" + (new Random().nextInt(100)));
setValue() 只能在主线程中使用,如果需要在子线程中修改数据,则需要使用 postValue()。
2.2 LiveData 总线
实际开发中通常将所有 LiveData 放在一个 LiveData 数据总线 —— LiveDataBus 上:
public class LiveDataBus {
private Map<String, MutableLiveData<Object>> bus;
private static LiveDataBus liveDataBus;
private LiveDataBus() {
bus = new HashMap<>();
}
public static LiveDataBus getInstance() {
if (liveDataBus == null) {
synchronized (LiveDataBus.class) {
if (liveDataBus == null) {
liveDataBus = new LiveDataBus();
}
}
}
return liveDataBus;
}
// 注册观察者,并从 bus 中取出对应的 MutableLiveData
public synchronized <T> MutableLiveData<T> with(String key, Class<T> type) {
if (!bus.containsKey(key)) {
bus.put(key, new MutableLiveData<Object>());
}
return (MutableLiveData<T>) bus.get(key);
}
}
设置数据和观察数据之前都需要先通过 with() 获取到 LiveData:
// 监听数据
LiveDataBus.getInstance().with("data", String.class)
.observe(this, new Observer<String>() {
@Override
public void onChanged(String string) {
Toast.makeText(TestActivity.this,string,Toast.LENGTH_LONG).show();
}
});
-------------------------------------------------------------------
// 设置数据
LiveDataBus.getInstance().with("data", String.class).postValue("data changed!");
3、原理
LiveData 的工作流程一般是:
- 注册 Observer,将其保存到 LiveData 的 mObservers 集合中
- 通过 setValue() 或 postValue() 修改 LiveData 内的数据
- LiveData 内的数据被修改,通知 Observer
下面按照流程顺序介绍工作原理。
3.1 注册观察者
LiveData 提供了 observe() 和 observeForever() 两个方法注册观察者:
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) {
// 要求该方法在主线程中使用
assertMainThread("observe");
// 如果 owner 已经被销毁就直接返回
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
// 将 observer 包装为 LifecycleBoundObserver 并存入 mObservers
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 如果 observer 此前没有被存过,existing 是 null,否则就是之前被存过的包装类对象
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// 不允许 observer 注册在不同的 owner 上
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
// 将包装类对象通过 LifecycleRegistry 注册到 owner 上
owner.getLifecycle().addObserver(wrapper);
}
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
// 要求该方法在主线程中使用
assertMainThread("observeForever");
// 将 observer 封装进 AlwaysActiveObserver 并存入 mObservers
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// 已经通过 observe() 与 LifecycleOwner 绑定过的 observer 不能再用 observeForever() 注册
if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
// 给 ObserverWrapper 的 mActive 赋值为 true 并分发一次数值
wrapper.activeStateChanged(true);
}
}
注册观察者时需要注意的信息:
- observe() 和 observeForever() 都必须在主线程中调用
- observe() 将 Observer 封装成 LifecycleBoundObserver 并注册到 LifecycleOwner,可以感知宿主的生命周期;observeForever() 将 Observer 封装成 AlwaysActiveObserver,没有与 LifecycleOwner 绑定,并设置一直处于活动状态
- 同一个 Observer 对象不能注册在不同的 LifecycleOwner 上,并且已经被 observe() 注册过的 Observer 不能再通过 observeForever() 注册
3.2 数据设置
LiveData 提供了两个方法设置其数据,其中 setValue() 只能在主线程中使用,而 postValue() 可以在子线程中使用,但实际上也是切换到主线程然后调用 setValue():
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
// mPendingData 可以被赋值多次,但是只有第一次赋值时会发送 mPostValueRunnable 任务
if (!postTask) {
return;
}
// 切换到主线程,实际上执行的是 DefaultTaskExecutor 的 postToMainThread()
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
// 取出 mPendingData 中的值交给 setValue()
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
ArchTaskExecutor.getInstance() 得到的是一个 DefaultTaskExecutor,而 DefaultTaskExecutor.postToMainThread() 会将任务 post() 到主线程的 Handler 中:
@Override
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = new Handler(Looper.getMainLooper());
}
}
}
mMainHandler.post(runnable);
}
所以综合看下来,LiveData 的 postValue() 就是在主线程中执行 setValue(),因此我们来看下 setValue() 的内容:
// LiveData 的版本号,初始值取 START_VERSION 的 -1
private int mVersion = START_VERSION;
@MainThread
protected void setValue(T value) {
// setValue() 必须只能在主线程
assertMainThread("setValue");
// 版本号加 1
mVersion++;
mData = value;
// 传 null 表示通知 LiveData 的所有观察者
dispatchingValue(null);
}
这里给 dispatchingValue() 传的是 null 而不是某个具体的 Observer,表示给当前 LiveData 内的 mObservers 中所有的观察者发通知,而不是仅通知某一个观察者:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// 如果已经在分发数据,又调用 dispatchingValue() 说明又有新的数据需要分发,那么将
// mDispatchInvalidated 置为 true 就直接跳过本次分发,这样会导致本次数据丢失
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
// 调用 activeStateChanged() 时会走这,只通知单个观察者
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
// setValue() 会走这,通知 mObservers 内的所有观察者
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() 完成的,在下一节详解该方法。
3.3 通知观察者
considerNotify() 通知观察者是有条件的:
- 观察者处于活动状态
- 观察者的版本号小于 LiveData 的版本号
具体代码如下:
private void considerNotify(ObserverWrapper observer) {
// 观察者不在活动状态,直接返回
if (!observer.mActive) {
return;
}
// 通过 shouldBeActive() 检查到观察者不在活动状态,返回
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// 观察者数据版本号不低于 LiveData 版本号,返回
if (observer.mLastVersion >= mVersion) {
return;
}
// 满足更新条件,更新版本号并回调观察者的 onChanged()
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
参数的 ObserverWrapper 是一个抽象类,它封装了原始的 Observer 并记录了它的状态和版本号:
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
// 观察者是否处于活动状态,实际上就是宿主是否处于活动状态
boolean mActive;
// 最新版本,默认值取 START_VERSION 的 -1
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
// 是否为活动状态,由子类决定
abstract boolean shouldBeActive();
...
}
在【3.1 注册观察者】中我们说过,observe() 和 observeForever() 将 observer 封装进了不同的包装类,分别是 LifecycleBoundObserver 和 AlwaysActiveObserver,二者都是 ObserverWrapper 的子类,但是对于活动状态的处理方式有所不同,需要分开来看。
LifecycleBoundObserver
LifecycleBoundObserver 是与生命周期绑定的观察者,在 ObserverWrapper 基础之上,将 LifecycleOwner 封装进来,以获取生命周期状态:
/**
* GenericLifecycleObserver 是 LifecycleEventObserver 的子接口,空的,
* 会在 lifecycle 3.0 上被移除
*/
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() {
// 至少是 STARTED 状态才认为是处于活动状态,实际上就是 STARTED 和 RESUMED
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
// 如果 LifecycleOwner,如 Activity/Fragment 已经被销毁,则移除观察者
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
// 直接调父类的 activeStateChanged(),传入宿主的状态(是否为活动状态)
activeStateChanged(shouldBeActive());
}
...
}
通过以上代码能看出:
- LifecycleOwner 的生命周期处于 STARTED 和 RESUMED 时是活动状态
- 如果 LifecycleOwner 已经被销毁,会从 mObservers 中移除该观察者
当 LifecycleOwner 的生命周期发生变化时,会经历如下步骤调用到 onStateChanged():
- LifecycleBoundObserver 在向 LifecycleRegistry 注册时,会被包装成 LifecycleEventObserver 封装在 ObserverWithState 中
- 当 LifecycleOwner 的生命周期发生变化时,会调用 LifecycleRegistry.ObserverWithState 的 dispatchEvent(),通过 LifecycleEventObserver.onStateChanged() 将生命周期事件通知给 LifecycleBoundObserver
如果对上述过程不熟悉,可以参考 生命周期感知组件 Lifecycle 中的【3.2 生命周期变化的感知与通知】一节。
在 onStateChanged() 内会通过 activeStateChanged() 将 LifecycleOwner 的生命周期状态传入:
// 子类没有重写 activeStateChanged()
private abstract class ObserverWrapper {
// 活动状态发生改变时被调用,newActive 为 true 表示为活动状态
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// 保存 LifecycleOwner 的状态
mActive = newActive;
// 更新 mActiveCount 状态前是否为非活动状态
boolean wasInactive = LiveData.this.mActiveCount == 0;
// 更新 mActiveCount
LiveData.this.mActiveCount += mActive ? 1 : -1;
// 从非活动状态到活动状态,回调 onActive()
if (wasInactive && mActive) {
onActive();
}
// 非活动状态回调 onInactive()
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
// 只有处于活动状态时才会给 LiveData 分发新值
if (mActive) {
dispatchingValue(this);
}
}
}
只有 LifecycleOwner 处于活动状态时才会调用 dispatchingValue() 通知当前的观察者,并且在 considerNotify() 内再次检查活动状态以及版本号,满足条件后才会回调 ObserverWrapper 内封装的 Observer 的 onChanged()。像这样在生命周期状态变化时通知观察者,可以保证:
- 从非活动状态转到活动状态时,观察者能立即获取到最新的 LiveData 数据
- 从活动状态转到非活动状态时,不通知观察者数据的更新
当然,如果是通过 setValue() 触发 dispatchingValue() 对 mObservers 内所有观察者执行 considerNotify(),也是只有处于活动状态的观察者能接收到 onChanged() 回调。
AlwaysActiveObserver
假如我们使用了 observeForever() 注册观察者,那么会被封装成 AlwaysActiveObserver 存入 LiveData 的 mObservers 集合。AlwaysActiveObserver 顾名思义,是永远处于活动状态的观察者,它重写的 shouldBeActive() 会固定返回 true:
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
return true;
}
}
此外,在 observeForever() 内调用 ObserverWrapper.activeStateChanged(true) 将 mActive 置为 true,这样当通过 setValue() 修改 LiveData 数据的时候,调用 dispatchingValue(null) 就会对 mObservers 中的所有观察者执行 considerNotify(),由于 AlwaysActiveObserver 的 mActive 和 shouldBeActive() 一直为 true,因此只要满足 mLastVersion 小于 LiveData 的 mVersion 这个条件,就可以回调 onChanged()。
需要注意的是,由于 AlwaysActiveObserver 没有向 LifecycleOwner 注册,因此只能通过手动调用 removeObserver() 来移除 AlwaysActiveObserver。
4、使用中遇到的问题
4.1 数据丢失问题
数据丢失的情况可能会有多种,一种情况是在老数据还没有分发完成的情况下,又产生了新的需要分发的数据,这时我们要回看一下 LiveData 的 dispatchingValue():
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// 如果已经在分发数据,又调用 dispatchingValue() 说明又有新的数据需要分发,那么将
// mDispatchInvalidated 置为 true 就直接跳过本次分发,这样会导致本次数据丢失
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
// 调用 activeStateChanged() 时会走这,只处理单个观察者
considerNotify(initiator);
initiator = null;
} else {
// setValue() 会走这,处理所有观察者
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
// 遍历 mObservers 取出所有观察者进行通知
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
第一次调用该方法,进入 do-while 循环前会将 mDispatchingValue 赋值为 true 表示正在分发数值,由于通过 setValue() 调用该方法时参数 initiator 传的是 null,所以会走 do-while 内的 else 分支通知所有观察者。
倘若就是在 for 循环之中再次 setValue() 进入 dispatchingValue(),那么 mDispatchInvalidated 会被设置为 true 然后直接返回。此时第一次调用的 dispatchingValue() 在 for 循环内由于 mDispatchInvalidated 为 true 跳出循环,这样就意味着有一部分观察者是没有收到第一次调用 dispatchingValue() 所分发的数值的。
结束 do 循环后,while 条件满足,会再次进入 do 循环,此时再进入 else 分支,通过 for 循环给所有观察者赋新值。
数据丢失还有另一种情况,调用 postValue() 设置数据时,设置数据的速度大于观察者的消费速度:
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
mPostValueRunnable 只有在被执行时才会去 mPendingData 中取值并传给 setValue() 进行设置,如果在该任务被执行前多次调用 postValue(),实际上只有任务被执行前的最后一次的 mPendingData 被真正的设置了,前面那些都被覆盖了,观察者也没有拿到。
当然了,观察者如果不处于活动状态,设置数据也是不会同步给观察者的。
4.2 粘性问题
粘性问题简单说就是 LiveData 上新注册的观察者接收到了在其注册之前 LiveData 被设置的值。举个例子:
public class StickyTestActivity extends AppCompatActivity {
private StickyViewModel stickyViewModel;
private Observer<String> observer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sticky_test);
observer = new Observer<String>() {
@Override
public void onChanged(String string) {
Toast.makeText(StickyTestActivity.this, string, Toast.LENGTH_SHORT).show();
}
};
stickyViewModel = new ViewModelProvider(this).get(StickyViewModel.class);
}
private void test() {
for (int i = 0; i < 10; i++) {
stickyViewModel.getData().setValue(String.valueOf(i));
if (i == 6) {
// 在 setValue(6) 之后注册的观察者,常理来讲不应该收到
// i = 6 这条消息,但是实际上会收到
stickyViewModel.getData().observe(this, observer);
}
}
}
public void buttonClick(View view) {
test();
}
}
----------------------------------------------------
public class StickyViewModel extends ViewModel {
private MutableLiveData<String> data;
public MutableLiveData<String> getData() {
if (data == null) {
data = new MutableLiveData<>();
}
return data;
}
}
在 test() 的 for 循环中不断向 LiveData 中发数据,当 i = 6 时注册 observer,按照常理来讲,注册动作发生在发送了 i = 6 这条数据之后,所以 observer 不应该收到这条数据,但实际情况是它收到了。这个是因为在注册观察者时,LiveData 的 observe() 会调用到 LifecycleRegistry 的 addObserver(),会调用 sync() 同步一次状态,从而进入状态分发流程,最终调用到 considerNotify():
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// 粘性的原因之一,观察者刚注册的时候版本是 -1,而 LiveData 因为刚刚在
// 执行 setValue() 时将其初始版本号 + 1 变为 0,这样观察者的版本号小于
// LiveData 的版本号,这里不会 return 就会调用 onChanged() 更新数据了
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
能在刚注册就收到之前的数据,观察者的版本号小于 LiveData 的版本号也是原因之一,它是解决粘性问题的切入点。我们可以通过反射修改观察者的版本号,使其等于 LiveData 的版本号,从而满足 considerNotify() 中的第三个 if 条件,使其直接返回不回调 onChanged()。参考代码如下:
public class StickyViewModel extends ViewModel {
private MutableLiveData<String> data;
public MutableLiveData<String> getData() {
if (data == null) {
data = new DisStickyMutableLiveData<>();
}
return data;
}
public static class DisStickyMutableLiveData<T> extends MutableLiveData<T> {
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
super.observe(owner, observer);
dismissSticky(this, observer);
}
private void dismissSticky(MutableLiveData<?> data, Observer<? super T> observer) {
try {
// 反射获取 LiveData 的版本号 mVersion
Class<?> liveDataClass = LiveData.class;
Method getVersionMethod = liveDataClass.getDeclaredMethod("getVersion");
if (!getVersionMethod.isAccessible()) {
getVersionMethod.setAccessible(true);
}
int liveDataVersion = (int) getVersionMethod.invoke(data);
// 去 LiveData 的 mObservers 中获取 observer 对应的 ObserverWrapper
Field mObserversField = liveDataClass.getDeclaredField("mObservers");
if (!mObserversField.isAccessible()) {
mObserversField.setAccessible(true);
}
Object mObservers = mObserversField.get(data);
// SafeIterableMap
Class<?> mObserversClass = mObservers.getClass();
Method getMethod = mObserversClass.getDeclaredMethod("get", Object.class);
if (!getMethod.isAccessible()) {
getMethod.setAccessible(true);
}
Map.Entry observerWrapperEntry = (Map.Entry) getMethod.invoke(mObservers, observer);
if (observerWrapperEntry != null) {
Object observerWrapper = observerWrapperEntry.getValue();
// observerWrapper.getClass() 获得的是 ObserverWrapper 的具体子类,如
// LifecycleBoundObserver、AlwaysActiveObserver,但是版本号 mLastVersion
// 是定义在父类 ObserverWrapper 中的,所以这里还得再 getSuperclass()
Class<?> superclass = observerWrapper.getClass().getSuperclass();
// 将观察者版本号设置成与 LiveData 的一致
Field mLastVersionField = superclass.getDeclaredField("mLastVersion");
if (!mLastVersionField.isAccessible()) {
mLastVersionField.setAccessible(true);
}
mLastVersionField.set(observerWrapper, liveDataVersion);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}