Jetpack LiveData

Jetpck 才是真的豪华全家桶

引言

  • LiveData 是一种可观察的数据存储器类。
  • LiveData 具有生命周期感知能力(遵循Activity、Fragment 或 Service等生命周期)。
  • LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

整体预览

Jetpack LiveData 概览图

1. 使用说明

1.1 特点

  • 确保界面符合数据状态
    • LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通对象。
  • 不会发生内存泄漏
    • 观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。
  • 不会因 Activity 停止而导致崩溃
    • 如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。
  • 不再需要手动处理生命周期
    • 界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。
  • 数据始终保持最新状态
    • 如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。
  • 适当的配置更改
    • 如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。
  • 共享资源
    • 可以使用单例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。

1.2 创建

参考下面【代码展示】: LiveData 对象通常存储在 ViewModel 对象中,并可通过 getter 方法进行访问。

1.3 观察

参考下面【代码展示】: 应用组件的 onCreate() 方法是开始观察 LiveData 对象的正确着手点。

1.4 更新

参考下面【代码展示】: MutableLiveData是LiveData的子类,公开 setValue(T) 和 postValue(T) 方法,修改存储在 LiveData 对象中的值。

【代码展示】:基础语法

// 1.2 创建
/**
 * LiveData 对象存储在 ViewModel 对象中
 * ps-1:避免 Activity 和 Fragment 过于庞大。现在,这些界面控制器负责显示数据,但不负责存储数据状态。
 * ps-2:将 LiveData 实例与特定的 Activity 或 Fragment 实例分离开,并使 LiveData 对象在配置更改后继续存在。
 */
class LiveModel : ViewModel() {
    val name: MutableLiveData by lazy {
        MutableLiveData()
    }

    val allLifeName: MutableLiveData by lazy {
        MutableLiveData()
    }
}

// 1.3 观察  &  1.4 更新
private const val TAG = "KJYR_LiveDataActivity"
class LiveDataActivity : AppCompatActivity() {
    //LiveModel定义
    lateinit var model: LiveModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)
        Log.d(TAG, "onCreate() called ")

        model = LiveModel()
        //基础使用:onCreate() 方法是开始观察 LiveData 对象:
        //ps-1:确保系统不会从 Activity 或 Fragment 的 onResume() 方法进行冗余调用。
        //ps-2:确保 Activity 或 Fragment 变为活跃状态后具有可以立即显示的数据。

        // 1.3 观察:创建可定义 onChanged() 方法的 Observer 对象
        val observer: Observer = Observer { name ->
            Log.d(TAG, "KJYR onChanged() : name = $name")
        }
        //1.3 观察: 使用 observe() 方法将 Observer 对象附加到 LiveData 对象
        // 1.3 观察:第一个参数是:LifecycleOwner(因为Activity实现了它,直接用即可)
        model.name.observe(this, observer)

        // 1.4 更新 : 非活跃状态不更新
        model.name.value = "onCreate"

        //1.3 观察:持久监听:observeForever
        model.allLifeName.observeForever { name ->
            Log.d(TAG, "KJYR onChanged() : all life name = $name")
        }
        model.allLifeName.value = "onCreate"
    }

    override fun onStart() {
        super.onStart()
        Log.d(TAG, "onStart() called")
        // 1.4 更新 : 如果在工作器线程中执行代码,可以改用 postValue(T) 方法来更新 LiveData 对象。
        // 1.4 更新 : 活跃状态更新
        model.name.value = "onStart"
    }
}

2. 高级用法

2.1 扩展

下面示例:名字上报(触发器->管理器->接收器)
核心:LiveData 活跃状态回调 onActive(),非活跃状态回调onInactive()

/**
 * 名字上报触发器
 */
class NameReportManager {

    private var listener: NameListener? = null

    private val handler = Handler(Looper.getMainLooper())

    private var count = 0;

    private val runnable: Runnable = object : Runnable {
        override fun run() {
            count++
            listener?.onNameReport("KJYR send : $count")
            handler.postDelayed(this, 1000)
        }
    }

    fun register(listener: NameListener) {
        this.listener = listener
        handler.postDelayed(runnable, 1000)
    }

    fun unregister(listener: NameListener) {
        this.listener = null
        handler.removeCallbacks(runnable)
    }

    interface NameListener {
        fun onNameReport(name: String)
    }
}

/**
 * 名字上报管理器(活跃状态有效)
 */
class NameLiveData : LiveData() {
    private val nameReport = NameReportManager()

    private val listener: NameListener = object : NameListener {
        override fun onNameReport(name: String) {
            value = "KJYR receive $name"
        }
    }

    //设置监听
    override fun onActive() {
        nameReport.register(listener)
    }

    //移除监听
    override fun onInactive() {
        nameReport.unregister(listener)
    }

    companion object {
        private lateinit var sInstance: NameLiveData

        fun get(): NameLiveData {
            sInstance = if (::sInstance.isInitialized) sInstance else NameLiveData()
            return sInstance
        }
    }
}

//名字上报接收器
class LiveDataActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)
        Log.d(TAG, "onCreate() called ")

        //扩展实现:名字上报接收器
        NameLiveData.get().observe(this, {name ->
            Log.d(TAG, "KJYR: Notify = $name")
        })
    }
}

2.2 转换

下面示例:获取名字长度(String -> Int)
核心:Lifecycle 软件包会提供 Transformations 类,Transformations 中通过 MediatorLiveData 来实现。当然可以使用 MediatorLiveData 实现更多的类型转换。

class LiveModel : ViewModel() {
    val name: MutableLiveData by lazy {
        MutableLiveData()
    }

    //map
    val length: LiveData = Transformations.map(name) { input ->
        input.length
    }

    //switch:switchMap() 的函数必须返回 LiveData 对象
    val nameLength: LiveData = Transformations.switchMap(name) { input ->
        MutableLiveData(input.length)
    }
}


class LiveDataActivity : AppCompatActivity() {
    //LiveModel定义
    lateinit var model: LiveModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)
        Log.d(TAG, "onCreate() called ")

        model = LiveModel()

        //转换:map
        model.length.observe(this) { length ->
            Log.d(TAG, "KJYR map: length = $length")
        }

        //转换:switchMap
        model.nameLength.observe(this) { nameLength ->
            Log.d(TAG, "KJYR switchMap: nameLength = $nameLength")
        }
    }

    override fun onStart() {
        super.onStart()
        Log.d(TAG, "onStart() called")
        model.name.value = "onStart"
    }
}

2.3 合并

下面示例:名字或者长度 改变 更新混合源信息(multiInfo
核心:MediatorLiveData 是 LiveData 的子类,允许合并多个 LiveData 源。只要任何原始的 LiveData 源对象发生更改,就会触发 MediatorLiveData 对象的观察者。

class LiveModel : ViewModel() {
    val name: MutableLiveData by lazy {
        MutableLiveData()
    }

    //map
    val length: LiveData = Transformations.map(name) { input ->
        input.length
    }

    //MediatorLiveData
    val multiInfo = MediatorLiveData()

    fun setMultiInfo() {
        multiInfo.addSource(name) { name ->
            multiInfo.value = "name = $name"
        }
        multiInfo.addSource(length) { length ->
            multiInfo.value = "value = $length"
        }
    }
}


class LiveDataActivity : AppCompatActivity() {
    //LiveModel定义
    lateinit var model: LiveModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)
        Log.d(TAG, "onCreate() called ")

        model = LiveModel()

        //合并多源:MediatorLiveData
        model.multiInfo.observe(this) { info ->
            Log.d(TAG, "KJYR MediatorLiveData: info = $info")
        }
        model.setMultiInfo()
    }

    override fun onStart() {
        super.onStart()
        Log.d(TAG, "onStart() called")
        model.name.value = "onStart"
    }
}

3. 原理分析

3.1 数据流向

3.1.1 数据流向 - 整体概览
Jetpack LiveData 原理分析 数据流向 整体概览图
3.1.2 数据流向 - 核心类关系
Jetpack LiveData 原理分析 数据流向 核心类关系
3.1.3 数据流向 - 订阅 observe
Jetpack LiveData 原理分析 数据流向 observe

【源码分析】- LiveData.observe()

    /**
     * 注册监听:活跃状态
     */
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
        assertMainThread("observe");    //注释:线程保证,主线程注册
        //注释:当前组件(比如activity)的LifecycleOwner是DESTROYED状态时,直接忽略
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }

        //注释:组装包装类(实现了LifecycleObserver接口),核心参数:LifecycleOwner + Observer
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

        //注释:链表(mObservers)添加键值对,存在:直接返回,不存在:添加,返回null
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);

        //注释:如果当前wrapper已经存在,且关联的不是当前owner,抛异常(因为观察者只能与一个owner绑定)
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }

        //注释:如果当前wrapper已经存在,并且关联的就是当前owner,则不需要额外注册,直接返回即可
        if (existing != null) {
            return;
        }

        //注释:通过当前owner,获得Lifecycle,添加注册
        owner.getLifecycle().addObserver(wrapper);
    }
3.1.4 数据流向 - 订阅 observeForever
Jetpack LiveData 原理分析 数据流向 observeForever

【源码分析】- LiveData.observeForever()

    /**
     * 注册监听:任何状态
     */
    @MainThread
    public void observeForever(@NonNull Observer observer) {
        assertMainThread("observeForever"); //注释:线程保证,主线程注册

        //注释:AlwaysActiveObserver 重写方法 shouldBeActive(), 忽略状态判断,任何状态都回调改变
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);

        //注释:如果当前wrapper已经存在,并且是LifecycleBoundObserver(生命周期约束组件),抛异常(与目标不符)
        if (existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }

        //注释:已经存在,且类型正常,则直接返回,不需要进行
        if (existing != null) {
            return;
        }

        //注释:因为是全状态可监听回调,所以不需要LifecycleOwner参与,直接调用触发状态设置即可,永久有效,除非主动移除
        wrapper.activeStateChanged(true);
    }
3.1.5 数据流向 - 订阅 activeStateChanged
Jetpack LiveData 原理分析 数据流向 activeStateChanged

(1)【源码分析】- LiveData.LifecycleBoundObserver

    //注释:受LifecycleOwner约束的监听器,UI常用组件
    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer observer) {
            super(observer);
            mOwner = owner;
        }

        //注释:LifecycleOwner是 STARTED 或者 RESUMED 状态时,才是活跃状态
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        //注释:监听 lifecycle 回调
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                                   @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            //注释: 收到 DESTROYED 状态会自动解除跟 owner 的绑定
            if (currentState == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
            //注释:while的意义(在活跃状态调用中,mOwner生命周期状态存在变更,及时处理)
            while (prevState != currentState) {
                prevState = currentState;
                activeStateChanged(shouldBeActive());   //注释:活跃状态变更调用
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

        //注释:是否与当前onwer相同
        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

(2)【源码分析】- LiveData.AlwaysActiveObserver

    //不依赖LifecycleOwner的活跃监听
    private class AlwaysActiveObserver extends ObserverWrapper {

        AlwaysActiveObserver(Observer observer) {
            super(observer);
        }

        @Override
        boolean shouldBeActive() {
            return true;    //注释:始终为活跃状态,专门为observeForever而生
        }
    }

(3)【源码分析】- LiveData.ObserverWrapper

    private abstract class ObserverWrapper {
        final Observer mObserver;    //注释:当前监听器
        boolean mActive;    //注释:是否为活跃状态
        int mLastVersion = START_VERSION;   //注释: 版本号(ObserverWrapper)

        ObserverWrapper(Observer observer) {
            mObserver = observer;
        }

        //注释: 是否为活跃状态,为了实现多态子类(受生命周期约束的,不受生命周期约束的)
        abstract boolean shouldBeActive();

        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }

        void detachObserver() {
        }

        //注释:活跃状态变更
        void activeStateChanged(boolean newActive) {
            //注释: 活跃状态未变更,则不处理
            if (newActive == mActive) {
                return;
            }
            //注释:当前活跃状态更新
            mActive = newActive;
            changeActiveCounter(mActive ? 1 : -1);
            //注释:存在活跃状态,则进行值的更新分发
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }

(4)【源码分析】- LiveData.changeActiveCounter()

     //注释:更改活动计数器
    @MainThread
    void changeActiveCounter(int change) {
        int previousActiveCount = mActiveCount;
        mActiveCount += change;
        if (mChangingActiveState) { //注释:活动计数器 已经在分发更新,则返回
            return;
        }
        mChangingActiveState = true;    //注释:活动计数器 分发标记 设置
        try {
            //注释:while循环的意义(在活跃状态的通知过程中,活跃数量存在变更时,
            //则再次进行活跃状态通知的检测与更新,防止状态遗漏)
            while (previousActiveCount != mActiveCount) {
                //注释:活动监听器 0 -> 1, 需要回调活跃通知
                boolean needToCallActive = previousActiveCount == 0 && mActiveCount > 0;
                //注释:活动监听器 1 -> 0, 需要回调非活跃通知
                boolean needToCallInactive = previousActiveCount > 0 && mActiveCount == 0;
                previousActiveCount = mActiveCount;
                if (needToCallActive) {
                    onActive();     //注释:活跃通知
                } else if (needToCallInactive) {
                    onInactive();   //注释:非活跃通知
                }
            }
        } finally {
            mChangingActiveState = false;   //注释:活动计数器 分发标记 清除
        }
    }

(5)【源码分析】- LiveData.dispatchingValue()

    /**
     *  分发更新
     */
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        //注释:正在分发过程中,则标记当前分发失效(mDispatchInvalidated)
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;   //注释:分发标识 开始
        do {
            mDispatchInvalidated = false;   //注释:当前分发失效清空
            if (initiator != null) {
                //注释:因为这个分支是 生命周期变更 触发(会有同状态忽略处理的保护,以及版本保护),
                //不需要参与分发实效的重试,通知完成糊,直接清空标记(initiator = null)
                //注释:ObserverWrapper.activeStateChanged 传入 this(ObserverWrapper)
                considerNotify(initiator);  //注释:考虑通知
                initiator = null;
            } else {
                //注释:setValue 出入 null, 通知 active状态的 mObservers
                for (Iterator, ObserverWrapper>> iterator =
                     mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());  //注释:考虑通知
                    //注释:在遍历过程中,如果遇到值更新(当前分发实效),则立马退出当前分发,
                    //重新从头开始遍历分发(也就是走到:while 处,再执行 do 中逻辑)
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;  //注释:分发标识 结束
    }

(6)【源码分析】- LiveData.considerNotify()

    /**
     * 判断通知
     */
    @SuppressWarnings("unchecked")
    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {    //注释:判断当前已保存状态为:非活跃状态,则不处理
            return;
        }

        //注释:获取当前最新状态,并检查,如果是非活跃状态,则更新以保存的状态,不进行后续处理。
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //注释:版本判断,只有值变更,才会进行
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;   //注释:更新版本
        //注释:回调mObserver的onChanged方法 结束
        observer.mObserver.onChanged((T) mData);
    }
3.1.6 数据流向 - 更新分发 setValue
Jetpack LiveData 原理分析 数据流向 setValue

【源码分析】- LiveData.setValue() / postValue()

    //注释:postValue()的异步更新
    private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {  //注释:线程安全更新
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue); //注释:最终回到setValue()方法
        }
    };

    //注释:子线程更新值(通过Handler分发到主线程)
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

    //注释:主线程更新值
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        //注释:每次更新数据,版本都会自增,默认值是 -1。
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

3.2 转换原理

3.2.1 转换原理 - Transformations.map

  创建 MediatorLiveData(MutableLiveData 的子类),通过 addSource() 方法将目标 LiveData 与 高阶函数创建的 Observer 进行关联,最后将转换后的值更新到 MediatorLiveData,并将 MediatorLiveData 返回,从而得到新的 LiveData,且与目标 LiveData 产生自关联。

【源码分析】- Transformations.map()

public static  LiveData map(
            @NonNull LiveData source,
            @NonNull final Function mapFunction) {
        final MediatorLiveData result = new MediatorLiveData<>();
        //注释:将传入的高阶函数,返回内容,设置到 MediatorLiveData
        result.addSource(source, new Observer() {
            @Override
            public void onChanged(@Nullable X x) {
                //注释:入参方法计算返回
                result.setValue(mapFunction.apply(x));
            }
        });
        return result;
    }
3.2.2 转换原理 - Transformations.switchMap

 与 map() 一样,只是多套了一层娃,达到高阶函数的类型匹配。

【源码分析】- Transformations.switchMap()

public static  LiveData switchMap(
            @NonNull LiveData source,
            @NonNull final Function> switchMapFunction) {
        final MediatorLiveData result = new MediatorLiveData<>();
        result.addSource(source, new Observer() {
            LiveData mSource;

            @Override
            public void onChanged(@Nullable X x) {
                //注释:入参方法计算返回
                LiveData newLiveData = switchMapFunction.apply(x);
                if (mSource == newLiveData) {
                    return;
                }
                if (mSource != null) {
                    result.removeSource(mSource);
                }
                mSource = newLiveData;
                //返回的LiveData, 同理再次套娃(将监听器与mSource关联)
                if (mSource != null) {
                    result.addSource(mSource, new Observer() {
                        @Override
                        public void onChanged(@Nullable Y y) {
                            result.setValue(y);
                        }
                    });
                }
            }
        });
        return result;
    }
3.2.3 转换原理 - Transformations.distinctUntilChanged

 原理相似,只是实现了具体业务场景:在更改之前保持不变。

3.2.4 转换原理 - MediatorLiveData

  Transformations 的核心是 MediatorLiveData 。MediatorLiveData 可以 无限套娃,进行 类型转换多源组合

【源码分析】- MediatorLiveData

public class MediatorLiveData extends MutableLiveData {
    private SafeIterableMap, Source> mSources = new SafeIterableMap<>();

    /**
     * 核心思想:添加拦截器(有个这个方法,就可以无限套娃)
     */
    @MainThread
    public  void addSource(@NonNull LiveData source, @NonNull Observer onChanged) {
        Source e = new Source<>(source, onChanged);
        Source existing = mSources.putIfAbsent(source, e);
        if (existing != null && existing.mObserver != onChanged) {
            throw new IllegalArgumentException(
                    "This source was already added with the different observer");
        }
        if (existing != null) {
            return;
        }
        if (hasActiveObservers()) {
            e.plug();
        }
    }

    @MainThread
    public  void removeSource(@NonNull LiveData toRemote) {
        Source source = mSources.remove(toRemote);
        if (source != null) {
            source.unplug();
        }
    }

    @CallSuper
    @Override
    protected void onActive() {  //注释:在有效状态时,进行监听
        for (Map.Entry, Source> source : mSources) {
            source.getValue().plug();
        }
    }

    @CallSuper
    @Override
    protected void onInactive() {   //注释:在无效状态时,取消监听
        for (Map.Entry, Source> source : mSources) {
            source.getValue().unplug();
        }
    }

    private static class Source implements Observer {
        final LiveData mLiveData;
        final Observer mObserver;
        int mVersion = START_VERSION;

        Source(LiveData liveData, final Observer observer) {
            mLiveData = liveData;
            mObserver = observer;
        }

        //注释:持久监听,减少没必要的生命周期对象依赖(因为在调用端就已经在活跃状态下)
        void plug() {
            mLiveData.observeForever(this);
        }

        void unplug() {
            mLiveData.removeObserver(this);
        }

        @Override
        public void onChanged(@Nullable V v) {
            //注释:版本有升级,才会进行通知更新
            if (mVersion != mLiveData.getVersion()) {
                mVersion = mLiveData.getVersion();
                mObserver.onChanged(v);
            }
        }
    }
}

3.3 消息总线

  LiveData 可以实现 消息总线(事件发布/订阅),但是要解决粘性事件的问题。可以通过反射,修改版本号去除粘性事件分发。具体实现参考 【美团技术团队 - LiveDataBus】。

4. 小结

  • 订阅类型:包括受生命周期约束(observe())和不受生命周期约束(observeForever())。
  • 订阅受生命周期约束的组件,只能与一个 LifecycleOwner 绑定。
  • 订阅受生命周期约束的组件,如果 LifecycleOwner 的状态为 DESTROYED ,则自动解绑。
  • 订阅受生命周期约束的组件,活跃状态切换,分发更新,所以 LiveData 自带粘性事件特征。
  • 订阅受生命周期约束的组件,活跃状态切换,分发更新,变更通知(在活跃状态和版本号同时满足的情况下)。
  • 属性值更新,分发更新,变更通知(在活跃状态和版本号同时满足的情况下)。
  • MediatorLiveData 可以 无限套娃,进行 类型转换 和 多源组合。常用工具类:Transformations 。

小编的博客系列

Jetpack 全家桶

你可能感兴趣的:(Jetpack LiveData)