Android jetpack LiveData (二) 原理篇

Android jetpack LiveData(二)原理篇

引言

上一篇我们学习了LifeCycle的简单使用Android jetpack LiveData(一)使用篇,那在这一篇主要学习LiveData的原理。

源码前置分析

核心类

LiveData:抽象类,定义了 LiveData 的基本行为和接口。
MutableLiveData:LiveData 的子类,提供了 setValue 和 postValue 方法用于更新数据。
Observer:观察者接口,用于定义数据更新时的回调方法。
LifecycleBoundObserver:实现了 Observer 接口,并且具有生命周期感知能力,确保只在合适的生命周期状态下通知观察者。

LiveData.java

定义了基本的数据观察和设置方法。

kotlin 复制代码
public abstract class LiveData<T> {
	@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
		...
    }

	@MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
    	...
    }
    protected void postValue(T value) {
        ...
    }

    @MainThread
    protected void setValue(T value) {
		...
    }

	protected void onActive() {

    }

    protected void onInactive() {

    }
}

MutableLiveData.java

LiveData的子类,

kotlin 复制代码
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);
    }
}

源码

我们按照使用的顺序来进行源码分析

第一步,定义LiveData对象
kotlin 复制代码
public MutableLiveData() {
        super();
    }

在核心类里面了解到MutableLiveData是LiveData的子类,所以我们去LiveData中看定义。在这里进行数据对象初始化。

kotlin 复制代码
public abstract class LiveData<T> {
	public LiveData(T value) {
        mData = value;
        mVersion = START_VERSION + 1;
    }
    public LiveData() { // 逻辑走这里
        mData = NOT_SET;
        mVersion = START_VERSION; // -1 (初始为-1 哦,后面会用到)
    }
}
第二步,观察LiveData数据

这个observe方法同样进入LiveData.java类中分析。

kotlin 复制代码
@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        // 1
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // 2
            return;
        }
        // 3
        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;
        }
        // 4
        owner.getLifecycle().addObserver(wrapper);
    }
    @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);
    }

这里我贴出了两个观察方法。
observe方法不需要自己手动清理观察者,当LifecycleOwner进入DESTROYED状态时,会自动移除观察者。

下面这个observeForever会一直观察,不需要传入lifecycleOwner,但是需要自己在不用时销毁removeObserver
// 1 :第一步要验证这个方法是否在主线程,证明该方法必须要在主线程调用。否则会抛出异常崩溃;
// 2 :第二步是判断当LifecycleOwner进入DESTROYED状态时,自动移除观察者。这个owner就是我们调用该方法时传入的owner;
// 3 :第三步出现了新的观察类LifecycleBoundObserver ,可以看到它实现了LifecycleEventObserver ,这个在我们学习Lifecycle的时候有讲过,主要是通过onStateChanged来观察生命周期,可以看下面的代码。
// 4 :核心。owner.getLifecycle().addObserver(wrapper);兜兜转转又回到了Lifecycle里面,把这个观察者添加到lifecycle里面。之前在Lifycycle原理篇有讲过,为lifycycle添加观察者,等lifecycleowner的生命周期变化,就会出发lifecycle event事件。

kotlin 复制代码
  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);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
                prevState = currentState;
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

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

接着往下看这个代码activeStateChanged(shouldBeActive());能看到当前状态是active的时候,会分发数据dispatchingValue(this);

kotlin 复制代码
		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);
            }
        }

dispatchingValue在LiveData中,这个方法用于将最新的值分发给观察者。

kotlin 复制代码
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
       // 首先检查是否正在分发值(mDispatchingValue为true)。
       // 如果是,则设置mDispatchInvalidated = true并立即返回。
       // 这意味着如果有递归调用,它会标记当前分发无效,让外层循环知道需要重新执行。
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    //循环结束后,检查mDispatchInvalidated标志。
                    // 如果为true,表示在分发过程中发生了无效化
                    //(通常是因为有新的数据变化导致需要重新分发),那么循环会再次执行,
                    //重新开始分发。否则退出循环。
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;  // 分发结束
    }

上述核心方法:considerNotify(initiator);
considerNotify 是 LiveData 中实际触发观察者回调的关键方法,它在 dispatchingValue 中被调用,用于向单个观察者派发数据observer.mObserver.onChanged((T) mData);确保只有在观察者处于正确状态且数据确实更新时才通知,同时维持了与 Lifecycle 组件的生命周期安全集成。

kotlin 复制代码
	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);
    }

这里最后就是我们回调的onChanged方法

那我们通过上面的分析就知道,livedata通过注册lifecycle观察者,在事件变更时能接收到变化。接下来我们继续看第三步;

第三步: 设置LiveData数据

使用setValue(主线程)/postValue(子线程)的形式去设置Livedata数据

因为postValue最终也会调用到setValue,所以我们从postValue()看起

kotlin 复制代码
    protected void postValue(T value) {
        boolean postTask;
        // 加同步锁考虑线程安全
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        // 在这里线程切换到主线程!!!
        ArchTaskExecutor.getInstance().postToMainThread(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);
        }
    };

看上述代码,看到在postValue()中将线程切换到主线程中,在主线程中又调用了setValue()。至此,我们就知道postValue最终也会通过runnable调用到setValue().

kotlin 复制代码
	@MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;   // 首次-1 -> 0
        mData = value;
        dispatchingValue(null); // null,进入for循环加到观察者里
    }

可以看到上面的setValue是必须要在主线程中调用的。如果在子线程调用会抛出异常。接着往下看。mVersion++,此时首次进入这个值从-1变成了0,同时传入wrapper是null(这个方法我们再第二步中也有描述)

kotlin 复制代码
	void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
            
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

首次:

mObservers可以有多个,是一个map集合。因此进入for循环全部加进来。

此时我们再去看considerNotify方法中的version

// mLastVersion 为-1

// mVersion为0,没法进入这里,往下走
后续

走传入的observer不为空的逻辑,直接调用。

kotlin 复制代码
		if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            }
kotlin 复制代码
	int mLastVersion = START_VERSION; // -1
	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、在订阅之前先设置好value, liveData.value = 20

2、mVersion++ 变为0

3、将设置的value传入mData,mData = value; 也就是 mData = 20,埋下伏笔

4、接着我们订阅观察者。

在LifecycleBoundObserver中,当我们的owener启动(生命周期变化)后,会通过activeStateChange分发当前数据!(见下图),这里就不走循环了,不需要再把observer加到map集合了。

5、后面就是considerNotify判断observer.mLastVersion >= mVersion.这里mLastVersion为-1,mVersion在2中变成了0,因此无法进入判断。mLastVersion设置为0,同时触发我们观察者的onChanged((T) mData)。这里的mData就是什么!!没错,就是那个在1中设置好的数据20!

小结

可以用这张图来表示。

下一步可能会讲讲怎么解决数据倒灌(黏性数据)。

ing...

相关推荐
我命由我123452 小时前
Android 多进程开发 - FileDescriptor、Uri、AIDL 接口定义不能抛出异常
android·java·java-ee·kotlin·android studio·android-studio·android runtime
阿拉斯攀登2 小时前
第 14 篇 显示驱动(MIPI/LVDS 屏)适配与调试,DRM 框架详解
android·驱动开发·rk3568·瑞芯微·rk安卓驱动
阿拉斯攀登3 小时前
第 18 篇 综合项目实战:基于 RK3568 的安卓智能门禁系统,全栈开发
android·驱动开发·瑞芯微·嵌入式驱动·rk3576·安卓驱动
阿巴斯甜4 小时前
Android LazyColumn的使用
android jetpack
UXbot4 小时前
APP原型生成工具测评
android·前端·人工智能·低代码·ios·开发·app原型
q***75184 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
泯仲5 小时前
从零起步学习MySQL || 第十五章:MySQL 可重复读隔离级别:它是如何工作的?是否完全解决幻读?
android·学习·mysql
qq_367719305 小时前
Android MQTT开源库paho.mqtt.android+MQTTX软件使用记录
android·java·开源·android mqtt开源库·mqttx软件使用
毕设源码-邱学长5 小时前
【开题答辩全过程】以 基于Android的仓库管理系统的设计与实现为例,包含答辩的问题和答案
android