RxBus實現(xiàn)過程詳解

1戒祠,什么是RxBus

rxbus不是什么框架朝蜘,它只是一個通過rxjava實現(xiàn)eventbus的類
在android中使用時叔收,它還還可以引用AndroidLifecycle來解決內(nèi)存溢出問題
它是觀察者模式的一種應(yīng)用选酗,方便了我們在不同頁面與不同線程間的通信

2哑子,代碼

RxBus的代碼實現(xiàn)


public class RxBus {
    private volatile static RxBus mDefaultInstance;
    //事件總線
    private final Subject<Object> mBus;
    //粘性事件存儲
    private final Map<Class<?>, Object> mStickyEventMap;

    private RxBus() {
        mBus = PublishSubject.create().toSerialized();
        mStickyEventMap = new ConcurrentHashMap<>();
    }

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

    /**
     * 發(fā)送事件
     */
    public void post(Object event) {
        mBus.onNext(event);
    }

    /**
     * 使用Rxlifecycle解決RxJava引起的內(nèi)存泄漏
     */
    public <T> Observable<T> toObservable(LifecycleOwner owner, final Class<T> eventType) {
        LifecycleProvider<Lifecycle.Event> provider = AndroidLifecycle.createLifecycleProvider(owner);
        return mBus.ofType(eventType).compose(provider.<T>bindToLifecycle());
    }

    /**
     * 判斷是否有訂閱者
     */
    public boolean hasObservers() {
        return mBus.hasObservers();
    }

    public void reset() {
        mDefaultInstance = null;
    }

    /**
     * 發(fā)送一個新Sticky事件
     */
    public void postSticky(Object event) {
        synchronized (mStickyEventMap) {
            mStickyEventMap.put(event.getClass(), event);
        }
        post(event);
    }

    /**
     * 根據(jù)傳遞的 eventType 類型返回特定類型(eventType)的 被觀察者
     * 使用Rxlifecycle解決RxJava引起的內(nèi)存泄漏
     */
    public <T> Observable<T> toObservableSticky(LifecycleOwner owner, final Class<T> eventType) {
        synchronized (mStickyEventMap) {
            LifecycleProvider<Lifecycle.Event> provider = AndroidLifecycle.createLifecycleProvider(owner);
            Observable<T> observable = mBus.ofType(eventType).compose(provider.<T>bindToLifecycle());
            final Object event = mStickyEventMap.get(eventType);

            if (event != null) {
                return observable.mergeWith(Observable.create(subscriber -> subscriber.onNext(eventType.cast(event))));
            } else {
                return observable;
            }
        }
    }

    /**
     * 根據(jù)eventType獲取Sticky事件
     */
    public <T> T getStickyEvent(Class<T> eventType) {
        synchronized (mStickyEventMap) {
            return eventType.cast(mStickyEventMap.get(eventType));
        }
    }

    /**
     * 移除指定eventType的Sticky事件
     */
    public <T> T removeStickyEvent(Class<T> eventType) {
        synchronized (mStickyEventMap) {
            return eventType.cast(mStickyEventMap.remove(eventType));
        }
    }

    /**
     * 移除所有的Sticky事件
     */
    public void removeAllStickyEvents() {
        synchronized (mStickyEventMap) {
            mStickyEventMap.clear();
        }
    }

}

事件實體類

public class MsgEvent {
    private String msg;

    public MsgEvent(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

接收事件(觀察者)

 RxBus.getInstance()
                .toObservable(this, MsgEvent.class)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<MsgEvent>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(MsgEvent msgEvent) {
                        text.setText("one " + msgEvent.getMsg());
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });

事件發(fā)送

RxBus.getInstance().post(new MsgEvent("Java"));

RxBus實現(xiàn)原理

初始化分析

首先,RxBus是一個單利模式鞋喇,這沒什么可以說的声滥,畢竟后面使用到RxBus需要是公共唯一的類。

事件總線侦香,現(xiàn)在來說一下Subject<Object> mBus落塑,這是一個事件總線,什么是事件總線呢罐韩?
在簡單觀察模式中憾赁,觀察者訂閱被觀察者,單被觀察者狀態(tài)或者數(shù)據(jù)發(fā)生變化時通知觀察者伴逸,這是一對一的關(guān)系缠沈。
但當觀察者和被觀察者是多個或者不確定數(shù)量的時候膘壶,這就需要一個總線來存儲這些觀察者和被觀察者错蝴,方便在發(fā)送通知的時候找到對應(yīng)的觀察者。

public class RxBus {
    
    ...
    
    //事件總線
    private final Subject<Object> mBus;
    
    private RxBus() {
        mBus = PublishSubject.create().toSerialized();
        mStickyEventMap = new ConcurrentHashMap<>();
    }
    
    ...
}

這里是通過Rxjava中的PublishSubject.create().toSerialized() 來創(chuàng)建總線用來存儲觀察者颓芭。簡單的就把它當做集合吧顷锰。

觀察者的創(chuàng)建分析

public class RxBus{
    
    ...
    
    /**
     * 使用Rxlifecycle解決RxJava引起的內(nèi)存泄漏
    */
    public <T> Observable<T> toObservable(LifecycleOwner owner, final Class<T> eventType) {
        LifecycleProvider<Lifecycle.Event> provider = AndroidLifecycle.createLifecycleProvider(owner);
        return mBus.ofType(eventType).compose(provider.<T>bindToLifecycle());
    }
    
    /**
     * 發(fā)送事件
    */
    public void post(Object event) {
        mBus.onNext(event);
    }
    ...
}

回顧觀察者創(chuàng)建代碼

 RxBus.getInstance()
                .toObservable(this, MsgEvent.class)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<MsgEvent>() { ... });

在觀察者創(chuàng)建時,先調(diào)用RxBus中的toObservable獲取一個回調(diào)事件類型為MsgEvent的被觀察者Observable亡问,其中傳入了LifecycleOwner官紫,
這個是為了防止當頁面關(guān)閉以后,訂閱事件還沒有結(jié)束州藕。

然后再執(zhí)行.subscribe()束世,并傳入一個新建的觀察者Observer,在subscribe的作用就是讓觀察者訂閱被觀察者

事件發(fā)送

執(zhí)行Subject的next進行發(fā)送

3,RxBus粘性事件

什么是粘性事件

一般情況都是先創(chuàng)建觀察者并加入到總線中床玻,然后在執(zhí)行事件發(fā)送毁涉,觀察者就可以收到相應(yīng)的事件

但是有時候也出現(xiàn)先發(fā)送事件,然后再創(chuàng)建觀察者锈死,這個時候就收不到之前的事件了贫堰,使用粘性事件就可以做到后創(chuàng)建的觀察者也可以收到之前的事件穆壕。

class RxBus{

    ...
    
    /**
     * 發(fā)送一個新Sticky事件
     */
    public void postSticky(Object event) {
        synchronized (mStickyEventMap) {
            mStickyEventMap.put(event.getClass(), event);
        }
        post(event);
    }

    /**
     * 根據(jù)傳遞的 eventType 類型返回特定類型(eventType)的 被觀察者
     * 使用Rxlifecycle解決RxJava引起的內(nèi)存泄漏
     */
    public <T> Observable<T> toObservableSticky(LifecycleOwner owner, final Class<T> eventType) {
        synchronized (mStickyEventMap) {
            LifecycleProvider<Lifecycle.Event> provider = AndroidLifecycle.createLifecycleProvider(owner);
            Observable<T> observable = mBus.ofType(eventType).compose(provider.<T>bindToLifecycle());
            final Object event = mStickyEventMap.get(eventType);

            if (event != null) {
                return observable.mergeWith(Observable.create(subscriber -> subscriber.onNext(eventType.cast(event))));
            } else {
                return observable;
            }
        }
    }
    
    ...
}

粘性事件實際就是創(chuàng)建一個Map<Class<?>, Object> mStickyEventMap,用于存儲所有發(fā)送過的粘性事件其屏,當創(chuàng)建粘性觀察者時喇勋,會從這map中知道對應(yīng)的EventType類型的被觀察者Observable,并返回
observable.mergeWith(Observable.create(subscriber -> subscriber.onNext(eventType.cast(event))))偎行,這是返回Observable時代碼發(fā)送了從map中對應(yīng)的事件川背,這樣新創(chuàng)建的觀察者也可以能馬上收到之前的事件

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市睦优,隨后出現(xiàn)的幾起案子渗常,更是在濱河造成了極大的恐慌,老刑警劉巖汗盘,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件皱碘,死亡現(xiàn)場離奇詭異,居然都是意外死亡隐孽,警方通過查閱死者的電腦和手機癌椿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來菱阵,“玉大人踢俄,你說我怎么就攤上這事∏缂埃” “怎么了都办?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長虑稼。 經(jīng)常有香客問我琳钉,道長,這世上最難降的妖魔是什么蛛倦? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任歌懒,我火速辦了婚禮,結(jié)果婚禮上溯壶,老公的妹妹穿的比我還像新娘及皂。我一直安慰自己,他們只是感情好且改,可當我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布验烧。 她就那樣靜靜地躺著,像睡著了一般又跛。 火紅的嫁衣襯著肌膚如雪碍拆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天,我揣著相機與錄音倔监,去河邊找鬼直砂。 笑死,一個胖子當著我的面吹牛浩习,可吹牛的內(nèi)容都是我干的静暂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼谱秽,長吁一口氣:“原來是場噩夢啊……” “哼洽蛀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起疟赊,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤郊供,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后近哟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驮审,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年吉执,在試婚紗的時候發(fā)現(xiàn)自己被綠了疯淫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡戳玫,死狀恐怖熙掺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情咕宿,我是刑警寧澤币绩,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站府阀,受9級特大地震影響缆镣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肌似,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一费就、第九天 我趴在偏房一處隱蔽的房頂上張望诉瓦。 院中可真熱鬧川队,春花似錦、人聲如沸睬澡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽煞聪。三九已至斗躏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間昔脯,已是汗流浹背啄糙。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工笛臣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人隧饼。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓沈堡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親燕雁。 傳聞我的和親對象是個殘疾皇子诞丽,可洞房花燭夜當晚...
    茶點故事閱讀 43,562評論 2 349

推薦閱讀更多精彩內(nèi)容

  • RxBus、EventBus因為解耦太徹底拐格,濫用的話僧免,項目可維護性會越來越低;一些簡單場景更推薦用回調(diào)捏浊、Subje...
    YoKey閱讀 15,658評論 32 81
  • 在正文開始之前的最后懂衩,放上 GitHub 鏈接和引入依賴的 gradle 代碼: Github: https://...
    松江野人閱讀 5,883評論 0 1
  • 轉(zhuǎn)一篇文章 原地址:http://gank.io/post/560e15be2dca930e00da1083 前言...
    jack_hong閱讀 910評論 0 2
  • 作者寄語 很久之前就想寫一個專題,專寫Android開發(fā)框架金踪,專題的名字叫 XXX 從入門到放棄 勃痴,沉淀了這么久,...
    戴定康閱讀 7,616評論 13 85
  • 文/葉孜 我是一只流浪貓,我遇見了一個人姐军。 她很溫柔铁材,會輕輕的抱著我, 她很漂亮奕锌,美麗的臉龐讓我一次就記住了她著觉, ...
    小小葉不愛謊言閱讀 313評論 0 0