LiveData 可以说是 Android 中前几年比较新的框架了,配合 ViewModel 使用效果极佳,也是 Android 推荐架构模式中用到的框架之一。
LiveData 是一种可观察的数据存储类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。它有以下的优势:
-
确保界面符合数据状态
LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知
Observer
对象。您可以整合代码以在这些Observer
对象中更新界面。这样一来,您无需在每次应用数据发生变化时更新界面,因为观察者会替您完成更新。 -
不会发生内存泄露
观察者会绑定到
Lifecycle
对象,并在其关联的生命周期遭到销毁后进行自我清理。 -
不会因 Activity 停止而导致崩溃
如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。
-
不再需要手动处理生命周期
界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。
-
数据始终保持最新状态
如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。
-
适当的配置修改
如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。
-
共享资源
您可以使用单例模式扩展
LiveData
对象以封装系统服务,以便在应用中共享它们。LiveData
对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察LiveData
对象。如需了解详情,请参阅扩展 LiveData。
但是它也存在一些缺点:
-
异步更新数据时,可能会导致数据丢失的问题。 -
组件在非活跃状态,同步调用无法触发观察者回调。
无论好坏,总结就是 LiveData 是一个自带生命周期管理、自带观察者模式,用来保存数据的对象,但它又不是持久化存储的。
使用
使用 LiveData 的步骤如下:
-
创建 LiveData 对象
val currentName: MutableLiveData = MutableLiveData<String>()
-
创建 Observer 对象
val nameObserver = Observer<String> { newName ->
// 当数据变化时,更新 TextView 文案.
nameTextView.text = newName
} -
使用 LiveData 的 observe() 方法将 Observer 作为参数绑定到 LiveData 对象。
currentName.observe(this@NameActivity, nameObserver)
-
更新 LiveData 的值,触发 nameObserver 回调 block 中的逻辑:
currentName.value = "新名字"
-
或者,在其他线程更新 LiveData 的数据:
currentName.postValue("新名字")
基本上这就是 LiveData 的完整使用了。
唯一需要注意的是,如果是在主线程更新数据,使用 setValue 方法;在其他线程更新数据,使用 postValue 方法。
原理
LiveData 的核心逻辑就是它表现出来的特性,即自动处理生命周期、通过观察中模式回调通知观察者和数据更新的两个方法。
核心逻辑
相关类和接口
LiveData 用到了一些类和接口,这些类和接口贯穿整个 LiveData 的核心逻辑,所以需要先介绍这些类和接口。
Observer
Observer 是一个简单的可以接收来自 LiveData 的回调的接口,它只有一个 onChanged 方法,代表具有接收数据后进行更新的能力。
public interface Observer<T> {
void onChanged(T t);
}
LifecycleOwner
LifecycleOwner 定义了生命周期的能力,凡是实现这个接口的方法都具有 Android 的生命周期能力,例如 Activity 、Fragment 都实现了这个接口。
public interface LifecycleOwner {
@NonNull
Lifecycle getLifecycle();
}
LifecycleEventObserver
LifecycleEventObserver 可以接收任何生命周期更改并将其分派给接收者的类。
public interface LifecycleEventObserver extends LifecycleObserver {
void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}
ObserverWrapper
LiveData 中的内部类,对 Observer 进行了封装,拓展了 LiveData 关心的活跃状态和一些其他能力。
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive; // 活跃状态
int mLastVersion = START_VERSION; // 更新版本
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
dispatchingValue(this);
}
}
}
而 ObserverWrapper 的实现有两个:
-
AlwaysActiveObserver,用于 observeForever 方法。 -
LifecycleBoundObserver,用于 observe 方法。
观察者注册
observe
LiveData 的核心方法是 observe(LifecycleOwner, Observer)
:
LiveData 的绑定生命周期和添加监听的方法是 observe :
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// 生命周期已进入 Destroy ,无需在进行任何处理
return;
}
// 将 owner 和 observer 包装成 LifecycleBoundObserver
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 保存到 SafeIterableMap 中,SafeIterableMap 是一个 LinkedList,它伪装成一个 Map 并支持在迭代期间进行修改。 它不是线程安全的。
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// 观察者已存在或无法绑定到 owner
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper); // 添加一个 LifecycleObserver,当 LifecycleOwner 更改状态时将通知该 LifecycleObserver。
}
在这个方法中,处理了生命周期对象的封装和观察者注册,最后一行代码可以在外部生命周期变化时,通知 Observer 。逻辑是:
-
检查 owner 的生命周期状态,如果 DESTROYED 直接 return 。 -
将 owner 和 observer 封装成 LifecycleBoundObserver 对象。 -
将 observer 保存到 SafeIterableMap 中。 -
如果 observer 已存在,或无法绑定到 owner ,抛出异常。 -
再次检查 existing 是否为 null ,为空直接 return 。 -
owner 的生命周期添加一个观察者,即封装好的 LifecycleBoundObserver 对象,它实现了 ObserverWrapper ,可以作为 ObserverWrapper 使用。
在 observe 方法中,有一个比较核心的类 LifecycleBoundObserver,它的继承关系是:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver
ObserverWrapper 在上文中提到过,是 Observer 的封装,增加了活跃状态的相关逻辑和更新版本管理能力。
LifecycleEventObserver 也在上文提及过,可以接收任何生命周期更改并将其分派给接收者的类。
LifecycleBoundObserver 实现了 LifecycleEventObserver ,具有了当生命周期变化时感知到的能力,通过 onStateChanged 方法来在感知到变化后做逻辑处理:
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
// 当生命周期为 DESTROYED 时,移除监听。
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
// 执行一个 while 循环,检查当前后状态不一致时
while (prevState != currentState) {
// 更新活跃状态和当前生命周期
prevState = currentState;
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
在 while 循环,当前后状态不一致时,说明生命周期发生了变化,这个时候就通过 activeStateChanged 方法来处理分发逻辑:
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// 立即设置活跃状态,因此我们永远不会向非活跃的 owner 发送任何内容
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1); // 更改计数
if (mActive) {
dispatchingValue(this);
}
}
如果处于活跃状态,通过 dispatchingValue 方法分发观察者:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// 正在分发 value ,此次分发无效
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
// 更新正在分发状态
mDispatchingValue = true;
// 不断循环,直到分发无效
do {
// 成功开始分发,更新分发失效状态为 false
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator); // 通过这里尝试通知观察者
initiator = null;
} else {
// initiator = null ,向 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 方法是真正触发 observer 的 block 逻辑的方法:
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
// 如果 observer 不应该变成活跃状态,通过 activeStateChanged 方法将状态更新为非活跃状态。
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// 数据更新的版本,防止老数据延迟回调导致新数据被老数据覆盖
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 回调 observer 的 onChanged block
observer.mObserver.onChanged((T) mData);
}
这部分逻辑主要实现的逻辑是在生命周期发生变化时,尝试更新数据。是一种被动地尝试回调观察者。
而主动的方式是通过 setValue 和 postValue 方法。
observeForever
LiveData 还提供了另一个方法,不绑定生命周期,一个简单的观察者模式。这意味着给定的观察者将接收所有事件并且永远不会被自动删除,需要手动调用 remove 方法来移除。
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
wrapper.activeStateChanged(true);
}
这里保证无需关心生命周期的核心逻辑在 AlwaysActiveObserver 对象中,AlwaysActiveObserver 中没有处理绑定生命周期相关的对象,而是直接将整个对象的活跃状态默认返回为 true ,从而保证了一直活跃。
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
return true;
}
}
数据更新
setValue
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
通过 setValue 方法更新数据要求在主线程中调用,每次更新会将 mVersion 进行 + 1 ,这个属性会用来做数据更新的版本校验。然后将新的值更新给 mData 。最后,通过 dispatchingValue(null)
,一个 null 参数,通知到所有 mObservers 中的数据。
setValue 不回调问题
在 considerNotify 方法中,存在一些条件:
private void considerNotify(ObserverWrapper observer) {
// 【1】
if (!observer.mActive) {
return;
}
// 【2】如果 observer 不应该变成活跃状态,通过 activeStateChanged 方法将状态更新为非活跃状态。
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// 【3】数据更新的版本,防止老数据延迟回调导致新数据被老数据覆盖
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 回调 observer 的 onChanged block
observer.mObserver.onChanged((T) mData);
}
【1】处很好理解,根据 observer 自身是否处理活跃状态来判断,mActive 的更新是通过 activeStateChanged 方法设置的。
条件【3】 也很好理解,通过增加了一个版本号防止老数据覆盖了新数据。
比较核心的是问题【2】,根据 ObserverWrapper 的实现不同,会有不同的逻辑。
在 observe 方法中,使用的是 LifecycleBoundObserver 对象,它的 shouldBeActive 方法实现是:
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
当生命周期在 STARTED 后,才变为活跃状态。
“
STARTED 代表的是 onStart 之后,onPause 之前
/**
* Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached in two cases:
* <ul>
* <li>after {@link android.app.Activity#onStart() onStart} call;
* <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call.
* </ul>
*/
STARTED,
postValue
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
postValue 要求在非主线程中发送消息给主线程,如果您在主线程执行 post 的任务之前多次调用此方法,则只会分派最后一个值。
postValue 中,首先加了个锁来处理数据更新逻辑。通过 postTask 局部变量,检查等待中的数据 mPendingData == NOT_SET
,这句代码的含义就是没有排队的数据。
如果存在等待中的数据,直接 return 而不是分发到主线程。这里就很容易产生一个疑问,为什么如果存在排队等待的数据,不发送到主线程而只是更新 mPendingData 呢?接着往下看。
而如果在 mPendingData 赋新的值之前是 NOT_SET
, 就可以直接发送一个 Runnable 到主线程。
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 中,对于上面的问题有了一个答案。mPostValueRunnable 的 run 分发中也是先加锁再更新数据:
-
加锁 -
取出 mPendingData 保存到临时变量 newValue -
将 mPendingData 设置为 NOT_SET -
解锁 -
调用 setValue 方法更新数据为临时变量 newValue
这里的第三步,将 mPendingData 设置为 NOT_SET 能够解答 mPendingData 存在值时,为什么不发送到主线程的问题。
一旦发送成功,就会将 mPendingData 设置为 NOT_SET ,而如果因为生命周期处于非活跃状态,此时不会立即更新数据,mPendingData 此时就不能直接发送到主线程更新,而是变成待处理的数据。
数据丢失问题
在 postValue 方法,我们分析出,如果 mPendingData 一直不等于 NOT_SET ,就不会将新的值发送到主线程,也就是不会发送通知给观察者。而 mPendingData 却一直会被覆盖新的值,这样就会出现数据丢失的问题。
总结
LiveData 的特点就是生命周期感知、观察者模式和数据更新的两种方式。
生命周期感知
对于生命周期的自动感知和处理是通过 observe 方法实现的,它的第一个参数是一个 LifecycleOwner 对象,代表具有生命周期的对象。
当生命周期发生变化时,通过回调 LifecycleEventObserver.onStateChanged 方法触发响应逻辑。而在 LiveData 中 LifecycleBoundObserver 实现了这个接口,并在感知到变化时,触发被动的触发观察者回调。
而如果无需关心生命周期,则可以使用 observeForever 方法来注册监听。
观察者模式
LiveData 的观察者是 Observer ,在 LiveData 内部进一步封装成 ObserverWrapper 。ObserverWrapper 中增加了活跃状态和版本,前者配合 LifecycleBoundObserver 实现了对于生命周期变化的逻辑。而版本则是为了防止异步更新导致老数据覆盖新数据的问题。
数据更新
数据更新分为主动更新和被动更新。
被动更新:每次生命周期从非活跃状态重新进入活跃状态时,会触发回调
主动更新:通过 setValue 和 postValue 方法进行主动更新,在主线程更新使用 setValue;在其他工作线程使用 postValue 。
原文始发于微信公众号(八千里路山与海):Android LiveData 超详细解读
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/60283.html