美文网首页
基于LiveData的仿EventBus快速实现:LiveDat

基于LiveData的仿EventBus快速实现:LiveDat

作者: 耗子JF | 来源:发表于2019-10-08 15:13 被阅读0次

对于黏性广播的问题,我们需要在之前的版本中,加上一个可选设置,默认为关闭状态;但是如何关闭这种功能,我们需要从LiveData事件分发机制里去查看:

    //源码查看,包括postValue最终都是调用SetValue接口实现
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;//这里有个一个版本,用于标记值是否发生变化,往后看就能发现其功能
        mData = value;
        dispatchingValue(null);
    }

    //接上面的value分发机制
    private 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<T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    //具体分发过程
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

    //具体分发过程
    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);//这里便是我们最终的分发调用点
    }

通过以上源码分析,我们可以看出,如果我们需要阻止在我们执行:

        LiveDataBus_Ver1.get()
                .with("bus1",String.class)
                .observe(this, new Observer<String>() {
                    @Override
                    public void onChanged(@Nullable String msg) {
                        LogW.d("LiveDataBus_Ver1"," msg received:"+msg);
                    }
                });

这个过程中,最小影响的原则下,我们只需要在调用.observe()方法的时候,满足observer.mLastVersion >= mVersion这个条件即可完美完成这个目的,而不会担心影响其余的正常事件分发机制,即observer.mLastVersion = mVersion将这段代码在我们调用.observe()执行一次即可,这个时候我们就需要通过hook来完成这个方案的实施,为此我们需要重写MutableLiveData的oberve方法:

public class MyMutableLiveData<T> extends MutableLiveData<T> {

        //该字段预留给LiveDataBus用于有需要黏性广播的用户
        private boolean isWithStick = false;

        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
            super.observe(owner, observer);
            if(!isWithStick){
                hookToCleanStick(observer);
            }
        }

        public void setWithStick(boolean withStick){
            this.isWithStick = withStick;
        }

        //此处代码为hook的重点段,有兴趣的可以对照源码来看
        private void hookToCleanStick(Observer<? super T> observer){
            try {
                //获取LiveData的mObservers(源码中我们所有的观察者都存放在这个Map里面)
                Field mObserversField = LiveData.class.getDeclaredField("mObservers");
                mObserversField.setAccessible(true);
                Object mObservers = mObserversField.get(this);

                //获取mObservers中observer对应的MAP.ENTITY
                //(通过获取我们注册的当前这个观察者对应的MAP.ENTITY,我们能够拿到上面源码里看到的对应的mVersion)
                Method methodGet = mObservers.getClass().getDeclaredMethod("get", Object.class);
                methodGet.setAccessible(true);
                Map.Entry entry = (Map.Entry) methodGet.invoke(mObservers,observer);//通过Map.Entity的get方法拿到对应的观察者
                
                //获取observer对应的observerWrapper
                Object observerWrapper = entry.getValue();

                //获取当前LivedData中mVersion的值
                Field mVersionField = LiveData.class.getDeclaredField("mVersion");
                mVersionField.setAccessible(true);
                Object mVersion = mVersionField.get(this);

                //更新observerWrapper中mLastVersion值为LiveData的mVersion值
                Field mLastVersion = observerWrapper.getClass().getSuperclass().getDeclaredField("mLastVersion");
                mLastVersion.setAccessible(true);
                mLastVersion.set(observerWrapper,mVersion);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

通过以上的hook代码,我们就完成了上面分析的observer.mLastVersion = mVersion这个操作。一下是完整版的LiveDataBus源码:

public class LiveDataBus {

    private final Map<String, MyMutableLiveData<Object>> bus;

    private LiveDataBus(){
        bus = new HashMap<>();
    }

    private static class SingletonHolder {
        /***单例对象实例*/
        static final LiveDataBus INSTANCE = new LiveDataBus();
    }

    public static LiveDataBus get() {
        return LiveDataBus.SingletonHolder.INSTANCE;
    }

    public MyMutableLiveData<Object> with(String key){
        return with(key, Object.class,false);
    }

    public MyMutableLiveData<Object> with(String key, boolean withStick){
        return with(key, Object.class,withStick);
    }

    public <T> MyMutableLiveData<T> with(String key, Class<T> clz){
        return with(key,clz,false);
    }

    public <T> MyMutableLiveData<T> with(String key, Class<T> clz, boolean withStick){
        if(!bus.containsKey(key)){
            MyMutableLiveData<Object> liveData = new MyMutableLiveData<>();
            bus.put(key,liveData);
        }
        MyMutableLiveData<Object> liveData = bus.get(key);
        liveData.setWithStick(withStick);
        return (MyMutableLiveData<T>) liveData;
    }

    public class MyMutableLiveData<T> extends MutableLiveData<T> {

        private boolean isWithStick = false;

        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
            super.observe(owner, observer);
            if(!isWithStick){
                hookToCleanStick(observer);
            }
        }

        public void setWithStick(boolean withStick){
            this.isWithStick = withStick;
        }

        private void hookToCleanStick(Observer<? super T> observer){
            try {
                //获取LiveData的mObservers
                Field mObserversField = LiveData.class.getDeclaredField("mObservers");
                mObserversField.setAccessible(true);
                Object mObservers = mObserversField.get(this);
                //获取mObservers中observer对应的MAP.ENTITY
                Method methodGet = mObservers.getClass().getDeclaredMethod("get", Object.class);
                methodGet.setAccessible(true);
                Map.Entry entry = (Map.Entry) methodGet.invoke(mObservers,observer);
                //获取observer对应的observerWrapper
                Object observerWrapper = entry.getValue();
                //获取当前LivedData中mVersion的值
                Field mVersionField = LiveData.class.getDeclaredField("mVersion");
                mVersionField.setAccessible(true);
                Object mVersion = mVersionField.get(this);
                //更新observerWrapper中mLastVersion值为LiveData的mVersion值
                Field mLastVersion = observerWrapper.getClass().getSuperclass().getDeclaredField("mLastVersion");
                mLastVersion.setAccessible(true);
                mLastVersion.set(observerWrapper,mVersion);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
Back:基于LiveData的仿EventBus快速实现:LiveDataBus

相关文章

  • 基于LiveData的仿EventBus快速实现:LiveDat

    该Bus实际上是参考了网上资料和相关视频而实现的,【如有雷同,绝对不是巧合】,同时也感谢晚上各种提供资料的广大程序...

  • 基于LiveData的仿EventBus快速实现:LiveDat

    对于黏性广播的问题,我们需要在之前的版本中,加上一个可选设置,默认为关闭状态;但是如何关闭这种功能,我们需要从Li...

  • LiveDataBus

    LiveDataBus是基于LiveData实现的类似EventBus的消息通信框架,它是基于LiveData实现...

  • LiveData使用

    一、前言: 1. 简介: 1、LiveData的简介 LiveData是一种类,持有可被观察的数据。LiveDat...

  • JetPack-LiveData源码解析

    LiveData原理分析 使用方法 这里借助谷歌官方文档来简单说明LiveData的用法: 创建一个LiveDat...

  • kotlin的一些坑点记录

    1,?:使用 这样的代码想要的结果:liveData ! = null 执行 LogUtil.i("liveDat...

  • 一篇讲明白EventBus

    先说EventBus是什么: EventBus是 基于 订阅/发布 模式实现的 基于事件的异步分发处理系统。 ...

  • 事件总线方案实践

    liveData实现事件总线 目录介绍 01.EventBus使用原理 02.RxBus使用原理 03.为何使用l...

  • Android 使用 LiveData 实现 EventBus

    绪论 本文是学习了大佬的文章后,自己去动手实践后写的一篇学习笔记。大佬的文章写得比较好,我自己去写未必描述得那么清...

  • Jetpack系列-LiveData使用和源码分析

    1 简介和简单使用 1.1 简介 LiveData是一种可观察的数据存储器类。与常规的可观察类不同,LiveDat...

网友评论

      本文标题:基于LiveData的仿EventBus快速实现:LiveDat

      本文链接:https://www.haomeiwen.com/subject/myipuctx.html