消息总线LiveDataBus,替换Rxbus/eventBus

前言

对于Android系统来说,消息传递是最基本的组件,每一个App内的不同页面,不同组件都在进行消息传递。在这之前,我们会用广播或者eventBus或者Rxbus去做消息的传递,但是现在开始我们可以用LiveDataBus了,相比前面这些消息总线框架,LiveDataBus有如下好处:
1.LiveDataBus可以减小APK包的大小 由于LiveDataBus只依赖Android官方Android Architecture Components组件的LiveData,没有其他依赖,本身实现只有一个类。而Rxbus借助Rxjava,需要引入Rxjava的支持库。

2.LiveDataBus可以感知activity的生命周期,没有内存泄漏的风险。

3.谷歌推荐。

Rxbus

在这里,还是先比较一下Rxbus

public class RxBus {

    private static volatile RxBus mDefaultInstance;

    private RxBus() {
    }

    public static RxBus getDefault() {
        if (mDefaultInstance == null) {
            synchronized (RxBus.class) {
                if (mDefaultInstance == null) {
                    mDefaultInstance = new RxBus();
                }
            }
        }
        return mDefaultInstance;
    }

    private final Subject<Object> _bus = PublishSubject.create().toSerialized();

    public void send(Object o) {
        _bus.onNext(o);
    }

    public Observable<Object> toObservable() {
        return _bus;
    }

    /**
     * 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者
     *
     * @param eventType 事件类型
     * @param <T>
     * @return
     */
    public <T> Observable<T> toObservable(Class<T> eventType) {
        return _bus.ofType(eventType);
    }

    /**
     * 提供了一个新的事件,根据code进行分发
     *
     * @param code 事件code
     * @param o
     */
    public void post(int code, Object o) {
        _bus.onNext(new RxBusMessage(code, o));

    }

    /**
     * 根据传递的code和 eventType 类型返回特定类型(eventType)的 被观察者
     * 对于注册了code为0,class为voidMessage的观察者,那么就接收不到code为0之外的voidMessage。
     *
     * @param code      事件code
     * @param eventType 事件类型
     * @param <T>
     * @return
     */
    public <T> Observable<T> toObservable(final int code, final Class<T> eventType) {
        return _bus.ofType(RxBusMessage.class)
                .filter(new Predicate<RxBusMessage>() {
                    @Override
                    public boolean test(RxBusMessage rxBusMessage) throws Exception {
                        //过滤code和eventType都相同的事件
                        return rxBusMessage.getCode() == code && eventType.isInstance(rxBusMessage.getObject());
                    }
                }).map(new Function<RxBusMessage, Object>() {
                    @Override
                    public Object apply(RxBusMessage rxBusMessage) throws Exception {
                        return rxBusMessage.getObject();
                    }
                }).cast(eventType);
    }

    /**
     * 判断是否有订阅者
     */
    public boolean hasObservers() {
        return _bus.hasObservers();
    }

}

在RxJava中有个Subject类,它继承Observable类,同时实现了Observer接口,因此Subject可以同时担当观察者和被观察者的角色,使用PublishSubject来创建一个Subject对象PublishSubject只有被订阅后才会把接收到的事件立刻发送给观察者。

在需要接收事件的地方,订阅该Subject对象,之后如果Subject对象接收到事件,则会发射给该观察者,此时Subject对象充当被观察者的角色。

完成了订阅,在需要发送事件的地方将事件发送给之前被订阅的Subject对象,则此时Subject对象作为观察者接收事件,然后会立刻将事件转发给订阅该Subject对象的订阅者,以便观察者处理相应事件,到这里就完成了事件的发送与处理。

最后就是取消订阅的操作了,RxJava中,订阅操作会返回一个Disposable对象,调用Disposable.dispose()以便在合适的时机取消订阅,防止内存泄漏。

LiveDataBus

public class LiveDataBusX {
    //存放订阅者
    private Map<String, BusMutiableLiveData<Object>> bus;
    private static LiveDataBusX liveDataBus = new LiveDataBusX();

    private LiveDataBusX() {
        bus = new HashMap();
    }
    public static LiveDataBusX getInstance() {
        return liveDataBus;
    }
    //注册订阅者
    public synchronized <T> BusMutiableLiveData<T> with(String key, Class<T> type) {
        if(!bus.containsKey(key)){
            bus.put(key,new BusMutiableLiveData<Object>());
        }
        return (BusMutiableLiveData<T>)bus.get(key);
    }

    public static class BusMutiableLiveData<T> extends MutableLiveData{
        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
            super.observe(owner, observer);
            hook(observer);
        }

        private void hook(Observer<? super T> observer) {
            try{
                //1.得到mLastVersion
                Class<LiveData> liveDataClass=LiveData.class;
                Field mObserversFeild=liveDataClass.getDeclaredField("mObservers");
                mObserversFeild.setAccessible(true);
                //获取到这个成员变量的对象
                Object mObserversObject=mObserversFeild.get(this);
                //得到map对应的class对象
                Class<?> mObserversClass=mObserversObject.getClass();
                //需要执行get方法
                Method get=mObserversClass.getDeclaredMethod("get",Object.class);
                get.setAccessible(true);
                Object invokeEntry=get.invoke(mObserversObject,observer);

                Object observerWraper=null;

                if(invokeEntry!=null && invokeEntry instanceof Map.Entry){
                    observerWraper=((Map.Entry)invokeEntry).getValue();
                }
                if(observerWraper==null){
                    throw new NullPointerException("observerWraper is null!");
                }
                //得到ObserveWraper的类对象 ,编译擦除问题
                Class<?> superclass=observerWraper.getClass().getSuperclass();
                Field mLastVersion=superclass.getDeclaredField("mLastVersion");
                mLastVersion.setAccessible(true);
                //2.得到mVersion
               Field mVersion=liveDataClass.getDeclaredField("mVersion");
               mVersion.setAccessible(true);
                //3.mLastVersion填到mVersion中
                Object mVersionValue=mVersion.get(this);
                mLastVersion.set(observerWraper,mVersionValue);

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

        }
    }

}

在使用这个LiveDataBus的过程中,订阅者会收到订阅之前发布的消息,这是不可接受的,在LifeData这篇文章中,讲述了原因,思路就是在把observerWraper的mLastVersion设置成个liveData的mVersion一样的值。

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