LiveData 完全指南:实践与背后原理全解

186 阅读13分钟

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 如何响应不同生命周期状态的变化:

  • 订阅过程: 当 LiveDataobserve 方法被调用时,它首先检查 LifecycleOwner 的状态。如果组件已被销毁,则忽略订阅。否则,创建一个 LifecycleBoundObserver 来包装 ObserverLifecycleOwner,并将其添加到内部观察者列表中。
  • 更新分发: 当 MutableLiveData 的值通过 setValuepostValue 方法更新时,LiveData 遍历其观察者列表,并通过调用 ObserveronChanged 方法来通知所有活跃的观察者。
  • 生命周期感知LifecycleBoundObserver 会监控 LifecycleOwner 的生命周期事件。根据生命周期状态(如 STARTEDRESUMED),它会激活或停用其自身,从而只在 LifecycleOwner 处于活跃状态时接收更新。

LiveData 的设计允许开发者编写更简洁的代码来处理数据更新,同时自动管理与生命周期相关的问题,防止内存泄漏和不必要的数据更新。通过详细分析其源码,开发者可以更好地理解其内部机制,并有效地在自己的项目中使用 LiveData。

LiveData源码解析

LiveData的实现基于几个关键的组件:LiveData, MutableLiveData, Observer, LifecycleOwner, 和 LifecycleBoundObserver

MutableLiveData

MutableLiveDataLiveData 的一个子类,提供了公开的 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);
    }
}

setValuepostValue

  • 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);
        }
    }
}

此方法检查观察者是否激活,并确保只有在数据有更新时才通知观察者。

生命周期感知

LifecycleBoundObserverObserverWrapper 的一个子类,它将观察者与 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,你可以编写出更清晰的代码。

参考博客: developer.android.com/topic/libra…

github.com/jhbxyz/Arti…