基于LiveData的仿EventBus快速实现:LiveDataBus 功能完善

对于黏性广播的问题,我们需要在之前的版本中,加上一个可选设置,默认为关闭状态;但是如何关闭这种功能,我们需要从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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355

推荐阅读更多精彩内容