一文读懂LiveData 粘性事件

一文读懂LiveData 的粘性事件

前言

说的通俗一点,就是先发送数据,后订阅,也可以接收到数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-klZR6QTN-1655823049309)(/Users/wyl/Documents/博客/文章/图片/tutieshi_640x360_2s.gif)]

这其实本是livedata 的一个特性,但是却给我们的日常使用带来了非常的不便,而且不提供API来解除粘性事件,这种做法确实不是很友好。

接下来,就带大家来揭秘一下LiveData 粘性事件的原理。

前方大量源码来袭,如有不适者,可以直接跳总结。

原理

首先我们从发送消息开始

liveData.postValue("页面1 发送的消息")

发送消息有两个方法:setValue和postValue

setValue 只能在主线程使用,postValue可以在任何线程使用,它被调用时,通过handler切换到主线程,再调用 setValue

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

这里有个 mVersion 要注意一下,后面会用到。然后就是通过 dispatchingValue 方法来分发消息了。

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

在这个方法里,主要是参数传的观察者是否为空,如果不为空,则向此观察者分发消息,如果为空,将会从观察者集合里面遍历观察者,进行分发。在这里,我们主要看 considerNotify 方法。

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

在我们前面提到 mVersion 用到了这里,和mLastVersion 做了比较,这点我们在下个步骤进行说明。

这就是我们全部发送消息的过程了,很简单明了,但是还不足以窥全貌,接下来我们分析另外一个步骤,监听。

liveData.observe(this) {
            Log.e("TAG", "onCreate: ")
            tv.setText("监听到的消息:$it")
        }
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        ............
        owner.getLifecycle().addObserver(wrapper);
    }

在这里,主要是对我们的 owner 和observer 做了一层包装,然后让 lifecycle 进行了监听。然后我们就看看 包装了点什么

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }
       .........
        @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();
            }
        }
        ............
    }

可以看到 LifecycleBoundObserver 继承了 ObserverWrapper ,实现了 LifecycleEventObserver 接口。

LifecycleEventObserver 接口 主要是当 lifecycle 状态改变的时候会感应到,并进行回调。

然后我们主要看看父类 ObserverWrapper :

    private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

        ObserverWrapper(Observer<? super T> observer) {
            mObserver = observer;
        }
        ............
        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);
            }
        }
    }

是不是看到了一个熟悉的面孔,就是我们上个步骤 提到的 mLastVersion ,它是在这里定义的,并且默认是-1;这里会在后文进行贯穿起来,先了解它的源头。

接下来,我们先继续走流程,还是LifecycleBoundObserver 类中,当状态改变的时候,会调用 onStateChanged 方法

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

当活跃状态改变的时候,会 调用 activeStateChanged :

void activeStateChanged(boolean newActive) {
    if (newActive == mActive) {
        return;
    }
    mActive = newActive;
    changeActiveCounter(mActive ? 1 : -1);
    if (mActive) {
        dispatchingValue(this);
    }
}

当状态是活跃状态的时候,会调用 dispatchingValue 进行数据分发,我们上文用到的分发是遍历所有观察者进行数据分发,这次是只分发当前观察者。

总结

接下来我们进行连贯一下:

首先发送数据 postValue ,次数会让进行 mVersion++ 操作,然后遍历观察者进行分发。

然后是进行监听操作,在进行监听的时候,会使用LifecycleBoundObserver 对观察者进行包装一下,在这个操作里面,LifecycleBoundObserver 的父类 ObserverWrapper 定义了 mLastVersion 为-1 。在数据最后进行分发的时候,mLastVersion 是小于 mVersion 的,所以未拦截,然后进行了数据的分发。

然后就产生了粘性事件。

在这里插入图片描述

关于粘性事件的解决方案现在也有很多,这里就不做赘述 ,可以参考一下这篇文章:

https://www.jianshu.com/p/d0244c4c7cc9

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不说话的匹诺槽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值