安卓源码分析(11)observable+lifecycle-aware的数据存储类Livedata

参考:https://developer.android.google.cn/topic/libraries/architecture/livedata?hl=zh-cn

1、概述

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 activity、fragment 或 service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者,从而避免了内存泄漏和不必要的 UI 更新。

遵循其他应用组件(如 activity、fragment 或 service)的生命周期怎么理解呢?LiveData 本身作为数据,它是没有生命周期的,通过观测组件的生命周期决定要不要进行数据通知。

下面是一些关于 LiveData 的特性和优势:

  • 生命周期感知: LiveData 可以感知关联的组件(如 Activity、Fragment)的生命周期状态,并根据这些状态自动开始或停止数据的更新,确保数据的更新操作与组件的生命周期相匹配。

  • 数据通知: 当 LiveData 中的数据发生变化时,它会通知所有观察者(如界面或其他组件),让它们可以及时更新自己的内容或状态。

  • 避免内存泄漏: LiveData 会自动绑定到相关的生命周期组件,并在组件销毁时自动进行清理,避免了潜在的内存泄漏问题。

  • 配置变更: LiveData 在配置变更(如屏幕旋转)时能够自动处理数据的恢复,保证数据的持久性。

  • 合并多个数据源(共享): LiveData 允许合并多个数据源,并通过观察数据的变化来自动更新 UI。

    扫描二维码关注公众号,回复: 17026087 查看本文章
  • 后台线程更新: LiveData 提供了 postValue 和 setValue 方法,可确保数据的更新操作在后台线程执行,避免阻塞主线程导致的界面卡顿问题。

  • 只读,数据只能在构造时设置一次,当然提供了可写的子类MutableLiveData

LiveData 是一个被广泛应用于 ViewModel 架构中的组件,通常与 ViewModel 配合使用来存储和管理界面相关的数据。它能够减少因配置变更而导致的数据丢失,并帮助开发者编写响应式的、可测试的代码。

2、源码分析

LiveData是一个模板类,包裹了存储的数据类型T,提供添加观察者接口,添加观察者,还需要提供一个LifecycleOwner。

LiveData观察者,说白了就是定义了回调接口 void onChanged(T t);,T是LiveData包裹的具体数据类型,LiveData在数据发生变化时,会调用观察者的 void onChanged(T t);回调,以进行数据变化通知,当然在进行数据通知前,会先判断观察者关联的生命周期(不一定是观察者的生命周期,而是观察者期望观察的对象的生命周期)是否是active,active的情况下才进行通知。

active是指处于 Lifecycle.State.STARTED or Lifecycle.State.RESUMED这两种状态。

从上面的分析可以看到,总共涉及三个对象,首先是LiveData即数据本身,其次是观察数据变化的Observer,按照我们的一贯想法,是不是关心这两类对象就可以了。

安卓的设计就是牛逼,提出了第三者,LifecycleOwner,在实际的业务里它通常是ui组件。数据发生变化,往往要通知到ui组件进行界面刷新,如果ui组件已经死亡,即inactive状态,那么就没有必要进行通知了,所以引入了Lifecycle,一个ui组件就是一个LifecycleOwner,即持有了一个Lifecycle。

数据变化,往往要经过中间商处理后才送往ui显示,这个中间商就是我们这里讨论的Observer,也就是说LiveData的Observer并不是ui组件本身,Observer除了观察LiveData之外,也要观察Lifecycle,所以它实现了LifecycleEventObserver的接口。

三者的关系图如下:

下面只展示了关键成员:

public abstract class LiveData<T> {
    
    
    private volatile Object mData; // 存储数据
    private int mVersion; // 数据版本,每次更新数据+1
    static final int START_VERSION = -1; // 数据的初始版本
    volatile Object mPendingData = NOT_SET; // 外部更新数据,并不会直接更新到mData,而是先更新到这里,再在线程里异步更新到mData
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>(); // 线程安全map存放观察者

添加Observer:

    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) 

移除Observer:

    public void removeObserver(@NonNull final Observer<? super T> observer) 

移除和该LIfecycle绑定的所有Observer:

    public void removeObservers(@NonNull final LifecycleOwner owner)

Observer的接口如下:

/**
 * A simple callback that can receive from {@link LiveData}.
 *
 * @param <T> The type of the parameter
 *
 * @see LiveData LiveData - for a usage description.
 */
public interface Observer<T> {
    
    
    /**
     * Called when the data is changed.
     * @param t  The new data
     */
    void onChanged(T t);
}

当然,LiveData也可以处理和生命周期没有关系的数据,只要构造一个永远观测到active的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 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;
        }
    }

数据版本字段

LiveData 提供 version 的概念是为了解决数据更新时可能出现的多次通知问题。当 LiveData 中的数据发生修改时,LiveData 会自动增加其 version 值,并将新的 version 值与旧的 version 值进行比较,以确定是否需要通知观察者。

在每个观察者注册时,它们都会获取 LiveData 的当前 version 值存放起来。当 LiveData 中的数据发生变化时,LiveData 会检查当前的 version 是否与之前观察者注册时的 version 值不同。如果不同,LiveData 将通知观察者数据已更新;如果相同,LiveData 将忽略该观察者的通知。这样可以避免观察者由于重复的通知而执行多次相同的操作,提升效率和性能。

通过使用 version 的机制,LiveData 确保只有实际发生数据变化时才会通知观察者,避免了不必要的数据传递和界面更新,提高了应用程序的响应性和效率。

异步数据更新
setValue是立刻更新数据,
同时提供了postValue异步更新数据,并不会直接更新到mData,而是先更新到mPendingData,再在线程里异步更新到mData。

注意,这两个方法都是protected的,所以LiveData是只读的。

活跃和失活通知

LiveData此外还提供了两个回调,
void onActive()和void onInactive(),他们会分别在有活跃的Observer和没有活跃的Observer时进行调用。

使用场景

LiveData 是一种被广泛应用于 Android 开发中的数据持有类,它具有生命周期感知、线程安全和轻量级等特点。LiveData 的使用场景包括但不限于以下情况:

  • 数据的观察和更新:LiveData 可以用来观察并响应数据的变化。当数据发生改变时,LiveData 会自动通知其观察者进行更新。这在需要实时展示数据的场景下非常有用,比如实时更新界面上的计数器、显示当前播放进度等。

  • 响应生命周期的数据持有:LiveData 可以感知 Activity 或 Fragment 的生命周期,并确保只在活跃状态下分发数据更新。这可以避免观察者在页面处于后台或已销毁状态时仍然接收到数据更新,从而提高应用程序的性能和稳定性。LiveData 具备对配置更改的处理能力,例如屏幕旋转时保存和恢复数据。

  • 架构组件的配合使用:LiveData 是 Android 架构组件的核心之一,可以与其他组件如 ViewModel、Room(持久化库)、ViewModel 和 Data Binding 等搭配使用。通过 LiveData,我们可以实现 ViewModel 和界面之间的数据共享和通信,以及实现数据持久化的功能。

  • 异步操作和后台线程:LiveData 提供了线程安全的数据更新机制,可以在后台线程中进行数据的更新,然后自动在主线程中通知观察者。这对于执行耗时操作、网络请求、数据库查询等场景非常有用,可以避免在主线程中执行耗时操作导致界面卡顿或 ANR(应用程序无响应)现象。

  • 跨组件通信:LiveData 可以用作跨组件通信的一种方式,不同组件之间可以通过观察 LiveData 来实现数据的共享和传递。比如,在不同的 Activity 或 Fragment 之间共享数据、在 Service 中更新 UI 等。

总结而言,LiveData 在 Android 开发中具有广泛的使用场景。它适用于需要观察和更新数据、响应生命周期并确保数据的安全性和一致性的场景,并与其他架构组件配合使用可以实现更加稳定和可维护的应用程序架构。

扩展
MutableLiveData 是 LiveData 的子类,它是一个可变的 LiveData 对象,可以用于在应用程序中存储和公开可变的数据。

与普通的 LiveData 不同,MutableLiveData 允许我们通过调用 setValue() 或 postValue() 方法来更新 LiveData 中的数据,其实就是修改了他们的访问权限。

/**
 * {@link LiveData} which publicly exposes {@link #setValue(T)} and {@link #postValue(T)} method.
 *
 * @param <T> The type of data hold by this instance
 */
@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {
    
    

    /**
     * Creates a MutableLiveData initialized with the given {@code value}.
     *
     * @param value initial value
     */
    public MutableLiveData(T value) {
    
    
        super(value);
    }

    /**
     * Creates a MutableLiveData with no value assigned to it.
     */
    public MutableLiveData() {
    
    
        super();
    }

    @Override
    public void postValue(T value) {
    
    
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
    
    
        super.setValue(value);
    }
}

猜你喜欢

转载自blog.csdn.net/HandsomeHong/article/details/132265654