關(guān)于RxBus的Stick特性探究

使用RxBus有一段時(shí)間了,記得剛使用的使用我在ActivityB中去注冊(cè)RxBus,這個(gè)時(shí)候ActivityB還沒(méi)有啟動(dòng),然后我在ActivityA中post事件后啟動(dòng)ActivityB,然而ActivityB并沒(méi)有接收到任何事件,當(dāng)時(shí)還郁悶了很久拖刃。

ActivityB接收不到事件的主要原因在于我們的ActivityB create之前發(fā)送了事件這個(gè)時(shí)候由于我們ActivityB并沒(méi)有創(chuàng)建,所以也沒(méi)有進(jìn)行事件注冊(cè)蕉堰,當(dāng)然收不到任何事件了,我當(dāng)時(shí)的做法是調(diào)用handler.postDelay(500)進(jìn)行延遲一下發(fā)送事件,這個(gè)時(shí)間是我測(cè)試ActivityB完全創(chuàng)建后的時(shí)間,這個(gè)時(shí)候由于ActivityB已經(jīng)創(chuàng)建并且注冊(cè)了事件访得,ActivityA發(fā)送的事件也可以被接收了,但是這種做法并不優(yōu)雅靠譜围小,因?yàn)锳ctivity創(chuàng)建時(shí)間多少完全不可預(yù)料,導(dǎo)致我們沒(méi)辦法去估計(jì)一個(gè)準(zhǔn)確的延遲事件,并且這種做法實(shí)在不優(yōu)雅锨阿。们豌。涯捻。浅妆。
所以我一直在想難道事件只能在Activity創(chuàng)建后才能發(fā)送嗎?可以不可在它創(chuàng)建前就發(fā)送,創(chuàng)建成功后接受到呢障癌?

我們看下面實(shí)現(xiàn)代碼

/**
 * Created by wubo on 2017/6/2.
 */

public class RxBus<T> {


    private static RxBus mRxBus;


    private PublishProcessor<T> mPublishProcessor;
    private ConcurrentHashMap<Class, T> mConcurrentHashMap;

    private RxBus() {
        mPublishProcessor = PublishProcessor.create();
        mConcurrentHashMap = new ConcurrentHashMap();

    }

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

    //register
    public Flowable<T> registerEvent(Class<T> clazz) {
        Flowable <T>tFlowable = mPublishProcessor.ofType(clazz);
        return tFlowable;
    }

    public void post(T event) {
        mPublishProcessor.onNext(event);
    }

    public Flowable registerStickEvent(final Class<T> clazz) {

        final T t = mConcurrentHashMap.get(clazz);
        if (t != null) {
            Flowable<T> tFlowable = mPublishProcessor.ofType(clazz);
            return tFlowable.mergeWith(Flowable.create(new FlowableOnSubscribe<T>() {
                @Override
                public void subscribe(FlowableEmitter<T> e) throws Exception {
                        e.onNext(t);
                }
            }, BackpressureStrategy.BUFFER));
        }

        return mPublishProcessor;

    }

    public void postStick(T event) {
        T t = mConcurrentHashMap.get(event.getClass());
        if (t == null) {
            mConcurrentHashMap.put(event.getClass(), event);
        }
        post(event);
    }

    public void removeAllStickEvent(){
        mConcurrentHashMap.clear();
    }

}

我們可以這么寫(xiě)凌外,為什么Stick事件注冊(cè)的時(shí)候需要合并一個(gè)流呢,因?yàn)槿绻覀冞@里首先需要返回一個(gè)Flowable提供訂閱的涛浙,那么如果我們直接返回mPublishProcessor的話我們?cè)趺唇邮盏絊tick事件呢康辑? 所以我們merge一個(gè)流當(dāng)我們注冊(cè)時(shí)就發(fā)送我們map中存入的stick事件。

這里還有個(gè)小問(wèn)題轿亮,當(dāng)我們訂閱一個(gè)被觀察者我們銷毀的時(shí)候需要解除訂閱疮薇,否則會(huì)繼續(xù)持有引用對(duì)象,導(dǎo)致內(nèi)存泄露.

Flowable<String> flowable = RxBus.getInstance().registerStickEvent(String.class);
        flowable.subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.e("wwwSecondActivity",s);
            }
        });

比如這段代碼哀托,我們?cè)赟econdActivity中使用RxBus注冊(cè)一個(gè)Stick事件惦辛,然后在MainActivity中開(kāi)開(kāi)心心的調(diào)用

RxBus.getInstance().postStick("MainActivity");

發(fā)送一個(gè)Stick事件
好我們看看Log打印日志
點(diǎn)擊按鈕跳到第二個(gè)界面

06-03 16:15:06.051 22060-22060/com.example.boboyuwu.rxbusstick E/wwwSecondActivity: MainActivity

吆西貌似效果不錯(cuò)哦~~等等我們按返回鍵退出這個(gè)界面然后再進(jìn)來(lái)試一試

06-03 16:16:46.714 22060-22060/com.example.boboyuwu.rxbusstick E/wwwSecondActivity: MainActivity
06-03 16:16:46.749 22060-22060/com.example.boboyuwu.rxbusstick E/wwwSecondActivity: MainActivity

這。仓手。這怎么回事胖齐,我只發(fā)送一次,怎么收到二個(gè)事件抱著大大的?我返回這個(gè)界面再進(jìn)來(lái)一次看看嗽冒,

06-03 16:18:00.767 22060-22060/com.example.boboyuwu.rxbusstick E/wwwSecondActivity: MainActivity
06-03 16:18:00.767 22060-22060/com.example.boboyuwu.rxbusstick E/wwwSecondActivity: MainActivity
06-03 16:18:00.814 22060-22060/com.example.boboyuwu.rxbusstick E/wwwSecondActivity: MainActivity

可以看到情況很不妙每次我們退出界面再進(jìn)來(lái)的時(shí)候這個(gè)事件就會(huì)多接收一次一直累加呀伙,我們分析一下問(wèn)題可能出現(xiàn)在哪。

在上一篇關(guān)于RxBus實(shí)現(xiàn)思考我們分析到當(dāng)我們使用subject onNext()去發(fā)送事件時(shí)候我們會(huì)發(fā)送到我們所有用subject 訂閱
的里面添坊,而我們第一次接收一次說(shuō)明我們訂閱了一次剿另,而退出來(lái)再進(jìn)來(lái)接收到二次說(shuō)明我們訂閱了二次,可你會(huì)疑惑我界面都退出了啊贬蛙,不錯(cuò)雨女,Rx是不會(huì)主動(dòng)幫你去解除你的訂閱關(guān)系的,所以當(dāng)你第一次訂閱的時(shí)候雖然你退出了但是被訂閱者引用還在RxBus的Subject里阳准,每訂閱并退出一次氛堕,這個(gè)引用會(huì)增加一個(gè),所以當(dāng)你發(fā)送事件的時(shí)候滿足類型會(huì)接收之前所有訂閱過(guò)的事件野蝇。

哪這多坑啊怎么辦呢讼稚?沒(méi)事rx可能也想到一點(diǎn)幫我提供一個(gè)CompositeDisposable類,它可以組裝我們所有的訂閱關(guān)系绕沈,然后統(tǒng)一進(jìn)行解綁锐想,我們可以創(chuàng)建一個(gè)方法

    public void addDispose(Disposable disposable){
        mCompositeDisposable.add(disposable);
    }

然后在onDesdory()中進(jìn)行統(tǒng)一解綁

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mCompositeDisposable!=null&&!mCompositeDisposable.isDisposed()){
            mCompositeDisposable.dispose();
        }
        RxBus.getInstance().removeAllStickEvent();
    }

這樣不管我們?cè)趺赐顺鼋缑娑紱](méi)有關(guān)系,我們當(dāng)前注冊(cè)事件的界面只會(huì)一對(duì)一的接收發(fā)送過(guò)來(lái)的事件乍狐。
isDisposed()是2.0新方法判斷CompositeDisposable有沒(méi)有解綁
如果已經(jīng)解綁就會(huì)返回true如果沒(méi)有的話就返回false
我們看看源碼是不是這樣

    @Override
    public void dispose() {
        if (disposed) {
            return;
        }
        OpenHashSet<Disposable> set;
        synchronized (this) {
            if (disposed) {
                return;
            }
            disposed = true;
            set = resources;
            resources = null;
        }

        dispose(set);
    }

    @Override
    public boolean isDisposed() {
        return disposed;
    }

isDisposed()返回disposed變量而當(dāng)我們調(diào)用dispose()丟棄我們綁定關(guān)系后 disposed = true;會(huì)被賦值為true

    @Override
    public boolean add(Disposable d) {
        ObjectHelper.requireNonNull(d, "d is null");
        if (!disposed) {
            synchronized (this) {
                if (!disposed) {
                    OpenHashSet<Disposable> set = resources;
                    if (set == null) {
                        set = new OpenHashSet<Disposable>();
                        resources = set;
                    }
                    set.add(d);
                    return true;
                }
            }
        }
        d.dispose();
        return false;
    }

add方法也是如此如果disposed是true的話說(shuō)明已經(jīng)解綁就不添加到集合里,直接把參數(shù)解綁然后返回false說(shuō)明添加失敗.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赠摇,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蝉稳,老刑警劉巖抒蚜,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掘鄙,死亡現(xiàn)場(chǎng)離奇詭異耘戚,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)操漠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)收津,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人浊伙,你說(shuō)我怎么就攤上這事撞秋。” “怎么了嚣鄙?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵吻贿,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我哑子,道長(zhǎng)舅列,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任卧蜓,我火速辦了婚禮帐要,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘弥奸。我一直安慰自己榨惠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布盛霎。 她就那樣靜靜地躺著赠橙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪愤炸。 梳的紋絲不亂的頭發(fā)上期揪,一...
    開(kāi)封第一講書(shū)人閱讀 52,682評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音摇幻,去河邊找鬼横侦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛绰姻,可吹牛的內(nèi)容都是我干的枉侧。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼狂芋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼榨馁!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起帜矾,我...
    開(kāi)封第一講書(shū)人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤翼虫,失蹤者是張志新(化名)和其女友劉穎屑柔,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體珍剑,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掸宛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了招拙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唧瘾。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖别凤,靈堂內(nèi)的尸體忽然破棺而出饰序,到底是詐尸還是另有隱情,我是刑警寧澤规哪,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布求豫,位于F島的核電站,受9級(jí)特大地震影響诉稍,放射性物質(zhì)發(fā)生泄漏蝠嘉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一均唉、第九天 我趴在偏房一處隱蔽的房頂上張望是晨。 院中可真熱鬧,春花似錦舔箭、人聲如沸罩缴。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)箫章。三九已至,卻和暖如春镜会,著一層夾襖步出監(jiān)牢的瞬間檬寂,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工戳表, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留桶至,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓匾旭,卻偏偏與公主長(zhǎng)得像镣屹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子价涝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,322評(píng)論 25 707
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理女蜈,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,715評(píng)論 18 139
  • 文章轉(zhuǎn)自:http://gank.io/post/560e15be2dca930e00da1083作者:扔物線在正...
    xpengb閱讀 7,034評(píng)論 9 73
  • 原文地址:http://gank.io/post/560e15be2dca930e00da1083 前言 我從去年...
    AFinalStone閱讀 2,197評(píng)論 5 23
  • 整個(gè)車廂在剎車聲后突然陷入一種死寂伪窖,前一秒大家還在尖叫著逸寓,此時(shí)都屏住了呼吸,驚魂未定地互相張望著覆山,都不知道發(fā)生了什...
    下一年的秋天閱讀 232評(píng)論 0 2