LiveData 机制详解

 一.消息监听机制

来个例子

        data.observe(this, observer)
        data.setValue(1)

上述代码,监听者会触发一次,我们来看看其中的缘由

在setValue里会给mVersion 成员变量加一,意味着数据的版本 加一,这个mVersion默认值是-1

        mVersion++;
        mData = value;
        dispatchingValue(null);

然后追查dispatchingValue函数的调用链,看它 是如何通知到监听者, 因为当初传的是空,所以会执行else语句

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

 

看看mObservers是什么,在 oberser函数里,把监听者和生命周期持有者封装存放在mObservers,所以遍历它来给所有注册的监听者传递最新的数据

        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);

 

这个considerNotify里,监听者有一个mLastVersion  成员变量,默认值是-1,与LiveData的mVersion相比较,如果大于等于mVersion,就表示数据版本更新,无需触发监听,否则就是把mVersion赋值给mLastVersion, 并且触发监听。


        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    

 

二.粘性消息机制

首先展示一个最简单能体现粘性消息的例子

        data.setValue(1)
        data.observe(this, observer)

上述代码依旧 能够触发监听者的回调,我们看看observe函数做了什么,把监听者 并和lifecycle持有者一起打包

        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        owner.getLifecycle().addObserver(wrapper);

找找 getLifecycle()获取的实例,我们需要从AppCompatActivity开始找,最后在FragmentActivity找到

    final LifecycleRegistry mFragmentLifecycleRegistry = new LifecycleRegistry(this);

然后来看看它的addObserver函数,它调用了这么一行代码,用于传递事件,继续追查

            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));

给 封装了lifecycle持有者发送数据,看 mLifecycleObserver实例在哪

            mLifecycleObserver.onStateChanged(owner, event);

得继续 看 lifecycleEventObserver

        ObserverWithState(LifecycleObserver observer, State initialState) {
            mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
            mState = initialState;
        }

这个判断很多,我 们需要 清楚这个observer的实例是啥

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver
public interface GenericLifecycleObserver extends LifecycleEventObserver 

 

 好了,我们再来看看lifecycleEventObserver 函数,说白了就是返回传进去的 实例了

        boolean isLifecycleEventObserver = object instanceof LifecycleEventObserver;
        if (isLifecycleEventObserver) {
            return (LifecycleEventObserver) object;
        }

然后看看onStateChanged函数调用了啥


            activeStateChanged(shouldBeActive());

继续

                dispatchingValue(this);

 

还继续,这个函数就很眼熟了,里面进行了版本比较,和触发更新,

considerNotify(initiator);

三.setValue

首先说说setValue,它的元注解MainThread规定了此函数在主线程执行,赋值时,版本加一

    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

我再给出一个使用的例子,你们 猜猜,触发监听多少次,结果是一次,为何,我们接着看看  dispatchingValue函数

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Log.v("zzw","onCreate")
        data.observe(this, observer)
        data.setValue(1)
        data.setValue(2)

    }

dispatchingValue最后会执行  considerNotify函数,这个函数虽然我之前贴出过几次,但没有说到它真正的厉害之处。

 首先需要提醒的是 LiveData不只是一个简单的被监听者,它依赖于生命周期。

 我在 if(!observer.mActive)这里打了断电,第一次 mActive为false,第二次为false,第三次为true。我调用了 两次setValue,为何有 三次调用到这里,说明还有其他 地方调用了。

    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }

        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }

 

 这里我对onStart和onResume都复写,打日志,再运行一次。这个说明第三次是在  onStart和onResume之间

onCreate
onStart
2
onResume

那我把 setvalue的代码放在onStart里,结果一样,如果放在onResume里,成功

onCreate
onStart
onResume
1
2

这里我再次打断点,considerNotify调用了三次,而且第一次因为LiveData的版本是-1,所以没有更新 数据。那这个多出的

一次调用是在onResume的开头。

首先我们看看,我们 在onStart和onCreate里的considerNotify调用是如何被中断的。因为前面打过断点,是因为observer.mActive为false,而这个变量默认没有赋值,也就是false,找找这个observer的 来源,来源是 LiveData.observer函数

        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);

 

这个observer的类是LifecycleBoundObserve,他有一个函数,看起来是分发状态,并且调用了父类的函数

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

  这里可以看出 mActive的值由传入的newActive决定,也就是 shouldBeActive函数决定

        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            if (mActive) {
                dispatchingValue(this);
            }
        }

这个shouldBeActive函数实质内容就是, 判断当前宿主的生命周期是否大于等于 onStart,如果 是的就返回true

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

所以我们之前的数据 传不到 监听者,是因为生命 周期不到。而每次生命周期变化,都会触发 onStateChanged函数

mLifecycleObserver.onStateChanged(owner, event);

 

 setValue的总结:值传递到监听者,有生命周期的限制(onStart以上,onDestroy以下)并且每次生命周期变化都会试着将值传递给监听者。

 

 四.postValue

postValue与setValue最大的 不同是,它可以在子线程传递数据。

而在子线程之间共享数据,最大的问题是线程同步,防止出现脏数据的问题

 首先看看postValue,在同步锁下它先把 值传给 mPendingData,如果我们是连调用几个postValue, 因为当前mPendingData已经被赋值了,所以就被return了,看看 postToMainThread做了啥

    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

因为这是一个代理模式,我找找他的实现类

    private ArchTaskExecutor() {
        mDefaultTaskExecutor = new DefaultTaskExecutor();
        mDelegate = mDefaultTaskExecutor;
    }

使用创建了一个在主线程运行的Handler,来运行runable

    @Override
    public void postToMainThread(Runnable runnable) {
        if (mMainHandler == null) {
            synchronized (mLock) {
                if (mMainHandler == null) {
                    mMainHandler = new Handler(Looper.getMainLooper());
                }
            }
        }
        //noinspection ConstantConditions
        mMainHandler.post(runnable);
    }

我们再回个头看看,运行的runable的内容,它把mPendingdata的值取出,然后赋予默认值,然后调用setValue。 这里需要 特别说明的是,之前也说过 连续调用几次postvalue, 只有第一次调用会 发送这个Runnable,但是这个 mPendingdata每次都会被赋值,所以这个节约了刷新次数。

    private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            setValue((T) newValue);
        }
    };

 

五.特殊情况解决

 

1.如果想让连续多次调用setValue,每次都触发更新,需要在onResume函数里调用

 

2.如果不想让分发LiveData设置的初始值,建议在设置初始值前,添加观察者

 

 

 

 

 

 

 

 

 

 

 

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页