LiveData 是 Android Jetpack 组件库中的一个非常核心的类,用于以生命周期感知的方式管理应用数据。本文将详细介绍 LiveData 的优点和缺点,展示如何在项目中配置和使用 LiveData,以及通过官方图例来解释其工作机制。
LiveData的核心概念和工作机制可以通过一些生活中的比喻来更直观地理解。这里我将提供几个比喻来帮助理解 LiveData 中涉及到的知识点:
1. 邮件订阅服务
想象 LiveData 是一种邮件订阅服务。当你订阅了一个杂志(注册观察者),只要杂志有新的出版物(数据更新),邮件服务就会送到你的邮箱(界面更新)。如果你搬家了(Activity或Fragment不活跃),邮件就不会送到旧地址,直到你通知邮局你的新地址(Activity或Fragment重新变活跃),邮件才能继续送达。
2. 无线电台
将 LiveData 想象成无线电台,而你的收音机就是观察者。只有当收音机开启并调到正确的频道(Activity或Fragment处于活跃状态),你才能听到广播(接收数据更新)。如果收音机关掉了(界面组件不活跃),即使电台继续广播,你也听不到任何内容。一旦你再次打开收音机并调到对应频道,你就能立即听到正在播放的内容,确保你没有错过任何信息。
环境配置与依赖
要开始使用 LiveData,首先确保你的项目已经集成了 Android Jetpack,并在 build.gradle 文件中添加以下依赖:
dependencies {
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
}
这个依赖包将允许你利用 LiveData 及其他与生命周期相关的组件。
LiveData 的优点
使用 LiveData 的好处多多,包括但不限于:
- 自动管理订阅关系:LiveData 能自动感知订阅者的生命周期,只有在订阅者活跃时才发送数据更新,有效避免内存泄露。
- 保证数据的最新性:无论何时,只要用户界面重新变为活跃状态,它都能立即显示最新的数据,这对于提升用户体验至关重要。
- 减少资源占用:LiveData 通过仅在需要时更新数据,帮助应用减少不必要的资源占用。
LiveData 的缺点
虽然 LiveData 提供了许多便利,但它也有一些局限性:
- 主线程限制:LiveData 的操作和数据更新必须在主线程进行,这可能会在处理大量数据或进行复杂更新时影响应用的响应性。
- 功能限制:对于需要处理复杂异步数据流的场景,LiveData 可能不足够强大。在这些情况下,可能需要使用如 Kotlin Flow 或 RxJava 等更适合的工具。
实际应用示例
在 ViewModel 中创建和观察 LiveData 对象是最常见的用法。以下是一个简单的例子,展示了如何在用户界面中显示和更新用户的名称:
class UserViewModel : ViewModel() {
val currentUserName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
}
class UserActivity : AppCompatActivity() {
private val userViewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val nameObserver = Observer<String> { newName ->
userNameTextView.text = newName
}
userViewModel.currentUserName.observe(this, nameObserver)
}
}
这个例子展示了 LiveData 如何在 ViewModel 和 Activity 之间桥接数据,保证了数据的及时性和准确性。
LiveData 的工作原理
LiveData 设计的核心是生命周期感知能力,这意味着它只在观察者(如活动或片段)处于活跃状态时更新数据。下图是从 Android 开发者官网提取的,展示了 LiveData 如何响应不同生命周期状态的变化:
- 订阅过程: 当
LiveData的observe方法被调用时,它首先检查LifecycleOwner的状态。如果组件已被销毁,则忽略订阅。否则,创建一个LifecycleBoundObserver来包装Observer和LifecycleOwner,并将其添加到内部观察者列表中。 - 更新分发: 当
MutableLiveData的值通过setValue或postValue方法更新时,LiveData遍历其观察者列表,并通过调用Observer的onChanged方法来通知所有活跃的观察者。 - 生命周期感知:
LifecycleBoundObserver会监控LifecycleOwner的生命周期事件。根据生命周期状态(如STARTED或RESUMED),它会激活或停用其自身,从而只在LifecycleOwner处于活跃状态时接收更新。
LiveData 的设计允许开发者编写更简洁的代码来处理数据更新,同时自动管理与生命周期相关的问题,防止内存泄漏和不必要的数据更新。通过详细分析其源码,开发者可以更好地理解其内部机制,并有效地在自己的项目中使用 LiveData。
LiveData源码解析
LiveData的实现基于几个关键的组件:LiveData, MutableLiveData, Observer, LifecycleOwner, 和 LifecycleBoundObserver。
MutableLiveData
MutableLiveData 是 LiveData 的一个子类,提供了公开的 setValue(T value) 和 postValue(T value) 方法用于更改和发布数据。这里是 MutableLiveData 类的简化版:
java
Copy code
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);
}
}
setValue 和 postValue
setValue(T value)方法必须在主线程调用,直接更新LiveData持有的数据,并通知所有活跃的观察者。postValue(T value)方法可以在任何线程调用,它会将一个任务排到主线程队列上,以更新LiveData持有的数据。
以下是 setValue 方法的实现:
java
Copy code
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
该方法首先确认调用线程是主线程,然后更新数据并递增版本号,最后调用 dispatchingValue(null) 来通知所有观察者。
观察者通知机制
LiveData使用 ObserverWrapper 来包装每个观察者,这些包装器管理观察者的激活状态并在数据变化时调用它们的 onChanged 方法。
java
Copy code
private void considerNotify(ObserverWrapper observer) {
if (observer.mActive && observer.shouldBeActive()) {
if (observer.mLastVersion < mVersion) {
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
}
}
此方法检查观察者是否激活,并确保只有在数据有更新时才通知观察者。
生命周期感知
LifecycleBoundObserver 是 ObserverWrapper 的一个子类,它将观察者与 LifecycleOwner 关联,确保只有在 LifecycleOwner 处于活跃状态时观察者才会接收到更新。
java
Copy code
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
}
shouldBeActive 方法检查 LifecycleOwner 的状态是否至少为 STARTED,从而决定观察者是否应该激活。
首先我们上面示例中的 LiveData.observe()方法开始。
//LiveDataActivity.kt
private val mContent = MutableLiveData<String>()
mContent.observe(this, Observer { content ->
tvContent.text = content
})
我们点进observe方法中去它的源码。
6.LiveData类
在LiveData的observe方法中
//LiveData.java
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
//1
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//2
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//3
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
//4
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
//5
owner.getLifecycle().addObserver(wrapper);
}
注释 1:首先会通过LifecycleOwner获取Lifecycle对象然后获取Lifecycle 的State,如果是DESTROYED直接 return 了。忽略这次订阅
注释 2 :把LifecycleOwner和Observer包装成LifecycleBoundObserver对象,至于为什么包装成这个对象,我们下面具体讲,而且这个是重点。
注释 3:把观察者存到 Map 中
注释 4:之前添加过LifecycleBoundObserver,并且LifecycleOwner不是同一个,就抛异常
注释 5:通过Lifecycle和添加 LifecycleBoundObserver观察者,形成订阅关系
总结:
到现在,我们知道了LiveData的observe方法中会判断 Lifecycle 的生命周期,会把LifecycleOwner和Observer包装成LifecycleBoundObserver对象,然后 Lifecycle().addObserver(wrapper) Lifecycle 这个被观察者会在合适的实际通知观察者的回调方法。
等等,什么时候通知,咋通知的呢?这个具体流程是啥呢?
回个神,我再贴下开始的示例代码。
class LiveDataActivity : BaseActivity() {
private val mContent = MutableLiveData<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_live_data)
//1
btnUpdate.setOnClickListener {
mContent.value = "最新值是:Update"
}
mContent.observe(this, Observer { content ->
tvContent.text = content
})
}
}
在点击按钮的时候 LiveData会调用setValue方法,来更新最新的值,这时候我们的观察者Observer就会收到回调,来更新 TextView。
所以接下来我们先看下 LiveData的setValue方法做了什么,LiveData还有一个postValue方法,我们也一并分析一下。
7.LiveData的setValue方法和postValue方法
7.1.先看setValue方法
//LiveData.java
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);//1
}
调用了dispatchingValue方法,继续跟代码
//LiveData.java
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
//1
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
//2
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
不管如何判断,都是调用了considerNotify()方法
//LiveData.java
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);//1
}
最终调用了observer.mObserver.onChanged((T) mData)方法,这个observer.mObserver就是我们的 Observer接口,然后调用它的onChanged方法。
到现在整个被观察者数据更新通知观察者这个流程就通了。
7.2.然后再看下postValue方法
子线程发送消息通知更新 UI,嗯?Handler 的味道,我们具体看下代码
//LiveData.java
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);//1
}
可以看到一行关键代码ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
点 **postToMainThread **方法进去看下
//ArchTaskExecutor.java
private TaskExecutor mDelegate;
@Override
public void postToMainThread(Runnable runnable) {
mDelegate.postToMainThread(runnable);//1
}
看到 mDelegate 是 TaskExecutor对象,现在目标是看下 mDelegate 的具体实例对象是谁
//ArchTaskExecutor.java
private ArchTaskExecutor() {
mDefaultTaskExecutor = new DefaultTaskExecutor();
mDelegate = mDefaultTaskExecutor;//1
}
好的,目前的重点是看下DefaultTaskExecutor是个啥,然后看它的postToMainThread方法
//DefaultTaskExecutor.java
private volatile Handler mMainHandler;
@Override
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = createAsync(Looper.getMainLooper());//1
}
}
}
mMainHandler.post(runnable);//2
}
注释 1:实例了一个 Handler 对象,注意构造参数 **Looper.getMainLooper()**是主线的 Looper。那么就可做到线程切换了。
注释 2:调用post 方法。
下面看下这个 Runnable
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
这里面的方法参数是mPostValueRunnable是个 Runnable,我们看下代码
//LiveData.java
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);//1
}
};
**注意:**postValue方法其实最终调用也是setValue方法,然后和setValue方法走的流程就是一样的了,这个上面已经分析过了。详情请看 7.1 小节
但是我们还不知道ObserverWrapper是啥,好那么接下来,我们的重点来了
我们要详细看一下LifecycleBoundObserver类了,它包装了LifecycleOwner和Observer,这就是接下来的重点内容了。
8.LifecycleBoundObserver类
再贴下一下代码,当LiveData调用observe方法时
//LiveData.java
@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);
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;
}
owner.getLifecycle().addObserver(wrapper);
}
注释 1 :用LifecycleBoundObserver对LifecycleOwner 和 Observer进行了包装
8.1.来看下LifecycleBoundObserver类,它是LiveData的内部类
//LiveData.java
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
}
两个参数,一个 owner被成员变量mOwner存储,observer参数被ObserverWrapper的 mObserver存储。
- LifecycleEventObserver是LifecycleObserver的子接口里面有一个onStateChanged方法,这个方法会在 Activity、Fragment 生命周期回调时调用,如果这么说不明看下这篇文章Android Jetpack组件Lifecycle基本使用和原理分析
- ObserverWrapper 是Observer包装类
我们接下来看下ObserverWrapper类
8.2.ObserverWrapper类
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
//1
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
//2
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;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
//3
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
//4
onInactive();
}
if (mActive) {
//5
dispatchingValue(this);
}
}
}
注:活跃状态指的是 Activity、Fragment 等生命周期处于活跃状态
注释 1:获取了我们的 Observer 对象,存储在 成员变量mObserver身上
注释 2:抽象方法,当前是否是活跃的状态
注释 3:可以继承 LiveData 来达到扩展 LiveData 的目标,并且是在活跃的状态调用
注释 4:可以继承 LiveData 来达到扩展 LiveData 的目标,并且是在非活跃的状态调用
注释 5:活跃状态,发送最新的值,来达到通知的作用, dispatchingValue(this)方法咋这么眼熟,对之前在 LiveData 调用 setValue 方法时,最终也会调用到此方法。那ObserverWrapper类中的dispatchingValue这个方法是在activeStateChanged方法中调用,那activeStateChanged啥时候调用呢?
我来看下ObserverWrapper的子类也就是最重要的那个类LifecycleBoundObserver,现在看它的完整代码
8.3.LifecycleBoundObserver完整代码
这里是关键代码了
//LiveData.java
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
//1
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//2
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//3
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
//4
mOwner.getLifecycle().removeObserver(this);
}
}
注释 1:判断当前的 Lifecycle 的生命周期是否是活跃状态,会在回调观察则 Observer 的时候进行判断,只有在活跃状态,才会回调观察者Observer的onChanged方法。
直接就回答了我们上面的这个问题LiveData 为什么只会将更新通知给活跃的观察者。非活跃观察者不会收到更改通知? 首先会通过LifecycleOwner获取Lifecycle对象然后获取Lifecycle 的State,并且状态大于STARTED。这里的State是和 Activity、Fragment 的生命周期是对应的,具体看这篇文章 Android Jetpack组件Lifecycle基本使用和原理分析 的第4.4小节,有详细的解释。
注释 2:onStateChanged每次 Activity、Fragment的生命周期回调的时候,都会走这个方法。
获取Lifecycle对象然后获取Lifecycle 的State如果为DESTROYED则移除观察者,在 Activity、Fragment的生命周期走到 onDestroy 的时候,就会取消订阅,避免内存泄漏。
注释 3:调用父类ObserverWrapper 的activeStateChanged方法,层层调用到观察者Observer的onChanged方法。(自己看下源码一目了然)
重点来了:在LiveData 调用setValue方法时,会回调观察者Observer的onChanged方法,Activity、Fragment的生命周期变化的时候且为活跃也会回调观察者Observer的onChanged方法。这就是为什么你在ActivityB页面,调用setValue方法,更新了value,在ActivityA 重新获取焦点时也同样会收到这个最新的值。
注释 4:移除观察者Observer,解除订阅关系。
到这个时候,LiveData 的 observer方法、setValue方法,整个流程就分析完了。
如果我们想不管生命周期,而是想在setValue的值发生改变的时候就能接受到通知,LiveData 还提供了一个observeForever方法
class LiveDataActivity : BaseActivity() {
private val mContent = MutableLiveData<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_live_data)
btnUpdate.setOnClickListener {
mContent.value = "最新值是:Update"
}
//只要在值发生改变时,就能接收到
mContent.observeForever { content ->
tvContent.text = content
}
}
}
8.4LiveData 的observeForever方法
这个方法比observe方法少一个LifecycleOwner参数,为啥呢?因为这个方法不需要感知生命周期,需要在setValue 值更新时立马收到回调。
来看下具体代码
//LiveData.java
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
//1
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);
}
注释 1 :这里用到的是AlwaysActiveObserver而 observe方法用到是LifecycleBoundObserver
看一下这个AlwaysActiveObserver
//LiveData.java
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
return true;
}
}
代码非常的简洁,在shouldBeActive方法中,直接 return true,这也太秀了吧
为啥直接返回 true 呢?因为这里不用管生命周期,永远都是活跃状态,所以这个方法叫observeForever
这个图解清楚地表明了 LiveData 如何智能地管理数据流,避免了在组件不活跃时进行不必要的数据更新,从而优化了性能和内存使用。
结语
LiveData 作为 Android 开发中的一个强大工具,提供了一种简洁有效的方法来设计响应式应用。尽管存在一些限制,但其优点使得它成为管理 UI 数据状态的首选方式。通过合理的使用 LiveData,你可以编写出更清晰的代码。