RxBus2.x的全面詳解

前言

在Android EventBus3.x的使用詳解一文中我們?nèi)嬷v解了使用EvenBus3.x解決進(jìn)程/界面通信袱衷。
本文將介紹另一個東西—>使用RxBus來實(shí)現(xiàn)進(jìn)程/界面通信。
閱讀本文胯舷,你需要提前了解RxJava,可以查看:
給 Android 開發(fā)者的 RxJava 詳解
Android響應(yīng)式編程框架—RxJava&RxAndroid2.0使用筆記

RxBus簡介

什么是RxBus妓盲?

RxBus 名字看起來像一個庫允耿,但它并不是一個庫,而是一種模式储笑,它的思想是使用RxJava來實(shí)現(xiàn)了EventBus 茧泪,而讓你不再需要使用 Otto 或者 GreenRobot 的 EventBus蜓氨。------ 給 Android 開發(fā)者的 RxJava 詳解

RxBus2.x就是基于RxJava2.x封裝實(shí)現(xiàn)的類。

為什么要使用RxBus队伟?

如上所說穴吹,我們可以通過封裝RxJava實(shí)現(xiàn)EventBus。
隨著RxJava在Android項(xiàng)目中的普及, 我們完全可以使用RxBus代替EventBus嗜侮,減少庫的引入港令,增加系統(tǒng)的穩(wěn)定性。
EventBus雖然使用方便锈颗,但是在事件的生命周期的處理上需要我們利用訂閱者的生命周期去注冊和取消注冊顷霹,這個部分還是略有麻煩之處。
而我們可以結(jié)合使用RxLifecycle來配置击吱,簡化這一步驟淋淀。
結(jié)合RxJava的強(qiáng)大能力和RxAndroid的進(jìn)程調(diào)度,RxBus有更多更強(qiáng)大的功能姨拥。

Demo&代碼

GitHub:https://github.com/DeMonLiu623/DeMon-RxBus

RxBus實(shí)現(xiàn)

Gradle

    implementation 'io.reactivex.rxjava2:rxjava:2.1.17' //RxJava
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' //RxAndroid

封裝RxJava實(shí)現(xiàn)RxBus

Subject有兩種用途:
做為observable向其他的observable發(fā)送事件
做為observer接收其他的observable發(fā)送的事件

我們要實(shí)現(xiàn):事件總線绅喉、事件發(fā)布者以及事件訂閱者渠鸽。首先Subject既可以作為被觀察者發(fā)送事件叫乌,也可以作為觀察者接收事件柴罐,而RxJava內(nèi)部的響應(yīng)式的支持實(shí)現(xiàn)了事件總線的功能。
可以使用PublishSubject.create().toSerialized();生成一個Subject對象憨奸。
如下代碼就實(shí)現(xiàn)了最基本的RxBus革屠。

public class RxBus {
    private volatile static RxBus mDefaultInstance;
    private final Subject<Object> mBus;

    private RxBus() {
        mBus = PublishSubject.create().toSerialized();
    }

    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);
    }

    /**
     * 根據(jù)傳遞的 eventType 類型返回特定類型(eventType)的 被觀察者
     */
    public <T> Observable<T> toObservable(final Class<T> eventType) {
        return mBus.ofType(eventType);
    }

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

    public void reset() {
        mDefaultInstance = null;
    }

}

使用RxBus

事件實(shí)體

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(MsgEvent.class).subscribe(new Observer<MsgEvent>() {
            @Override
            public void onSubscribe(Disposable d) {
                
            }

            @Override
            public void onNext(MsgEvent msgEvent) {
                //處理事件
            }

            @Override
            public void onError(Throwable e) {
                  
            }

            @Override
            public void onComplete() {

            }
        });

發(fā)送事件

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

與EventBus對比,除了訂閱事件的消息處理排宰,使用基本一樣似芝。
至于EventBus的線程模型,我們完全可以使用RxJava 的線程控制Scheduler來實(shí)現(xiàn)板甘,具體可以參考上面RxJava的使用兩篇文章党瓮。

RxBus內(nèi)存泄漏

使用RxJava發(fā)布一個訂閱后,當(dāng)頁面被finish盐类,此時訂閱邏輯還未完成寞奸,如果沒有及時取消訂閱,就會導(dǎo)致Activity/Fragment無法被回收在跳,從而引發(fā)內(nèi)存泄漏枪萄。
EventBus為了解決這個問題,要求我們根據(jù)訂閱者的生命周期注冊和取消注冊猫妙。所以在RxBus中我們也可以這樣操作瓷翻。

簡單處理

使用一個CompositeDisposable存儲當(dāng)前所有的訂閱,然后再onDestroy()中將其dispose()割坠。

private CompositeDisposable compositeDisposable;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
compositeDisposable = new CompositeDisposable();
        RxBus.getInstance().toObservable(MsgEvent.class).subscribe(new Observer<MsgEvent>() {
            @Override
            public void onSubscribe(Disposable d) {
                compositeDisposable.add(d);
            }

            @Override
            public void onNext(MsgEvent msgEvent) {
                //事件處理
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unbinder.unbind();
        if (compositeDisposable!=null && !compositeDisposable.isDisposed()){
            compositeDisposable.dispose();
        }
    }

RxLifecycle

Rxlifecycle 是trello開發(fā)的用于解決RxJava引起的內(nèi)存泄漏的開源框架齐帚。
GitHub地址:https://github.com/trello/RxLifecycle
該框架為了適應(yīng)不同的場景,開發(fā)了不同的版本,具體的可以查看GitHub文檔:

// RxLifecycle基礎(chǔ)庫
implementation 'com.trello.rxlifecycle2:rxlifecycle:2.2.2'

// Android使用的庫彼哼,可以綁定特定的生命周期
//需繼承RxActvivty使用
implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.2'

// Android組件庫对妄,里面定義了例如RxAppCompatActivity、RxFragment之類的Android組件
// 須繼承RxAppCompatActivity沪羔、RxFragment使用
implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.2'

// 預(yù)先編寫的支持首選項(xiàng)片段饥伊,將其子類化為提供者
implementation 'com.trello.rxlifecycle2:rxlifecycle-components-preference:2.2.2'

// Android使用的庫,須繼承NaviActivity使用
implementation 'com.trello.rxlifecycle2:rxlifecycle-navi:2.2.2'

// 使用Android生命周期作為提供者
//無需繼承蔫饰,任何有聲明周期的組件都可以直接使用
implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.2.2'

// Kotlin語法 
implementation 'com.trello.rxlifecycle2:rxlifecycle-kotlin:2.2.2'

//在Kotlin語法琅豆,使用Android生命周期 
implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle-kotlin:2.2.2'

如果我們自己有BaseActivity,所以不能繼承RxActvivty篓吁,RxAppCompatActivity茫因、RxFragment,NaviActivity杖剪。
為了保持代碼的靈活性冻押,我們使用:

// 使用Android生命周期作為提供者
implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.2.2'

修改RxBus驰贷,添加如下代碼:
使用compose(this.bindToLifecycle())方法綁定Activity的生命周期,在onStart方法中綁定洛巢,在onStop方法被調(diào)用后就會解除綁定括袒,以此類推。
如果在onPause/onStop方法中綁定稿茉,那么就會在它的下一個生命周期方法(onStop/onDestory)被調(diào)用后解除綁定锹锰。

綁定 銷毀
onCreate onDestory
onStart onStop
onResum onPause
onPause onStop
onStop onDestory
 /**
     * 使用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());
    }

訂閱事件時,添加上下文this即可綁定生命周期漓库,自動取消訂閱:

RxBus.getInstance().toObservable(this,MsgEvent.class).subscribe(new Consumer<MsgEvent>() {
            @Override
            public void accept(MsgEvent msgEvent) throws Exception {
                //處理事件
            }
        });

RxBus的粘性事件

EventBus有粘性事件恃慧,RxBus也可以實(shí)現(xiàn)。
修改RxBus修改&添加如下代碼:

private final Map<Class<?>, Object> mStickyEventMap;

    private RxBus() {
        mBus = PublishSubject.create().toSerialized();
        mStickyEventMap = new ConcurrentHashMap<>();
    }
  /**
     * 發(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(new ObservableOnSubscribe<T>() {
                    @Override
                    public void subscribe(ObservableEmitter<T> subscriber) throws Exception {
                        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();
        }
    }

RxBus完整代碼

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;
    }


    /**
     * Stciky 相關(guān)
     */

    /**
     * 發(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(new ObservableOnSubscribe<T>() {
                    @Override
                    public void subscribe(ObservableEmitter<T> subscriber) throws Exception {
                        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();
        }
    }

}

Demo

該Demo演示了使用RxBus完成Activty與Fragment的通信渺蒿。

public class RxActivity extends AppCompatActivity {

    @BindView(R.id.java)
    Button java;
    @BindView(R.id.android)
    Button android;
    @BindView(R.id.rx_layout)
    FrameLayout rxLayout;
    private FragmentManager fragmentManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rx);
        ButterKnife.bind(this);
        fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.add(R.id.rx_layout, new RxFragment());
        transaction.commit();
    }

    @OnClick({R.id.java, R.id.android})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.java:
                RxBus.getInstance().post(new MsgEvent("Java"));
                break;
            case R.id.android:
                RxBus.getInstance().post(new MsgEvent("Android"));
                break;
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/java"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Java" />

        <Button
            android:id="@+id/android"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Android" />
    </LinearLayout>

    <FrameLayout
        android:id="@+id/rx_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
public class RxFragment extends Fragment {
    @BindView(R.id.text)
    TextView text;
    Unbinder unbinder;
    private View view;
    @SuppressLint("CheckResult")
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_rx, container, false);
        unbinder = ButterKnife.bind(this, view);
    
        RxBus.getInstance().toObservable(this,MsgEvent.class).subscribe(new Consumer<MsgEvent>() {
            @Override
            public void accept(MsgEvent msgEvent) throws Exception {
                //處理事件
            }
        });
        return view;
    }

}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:text="RxFragment"
    android:textSize="18sp" />

<TextView
    android:id="@+id/text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:textSize="16sp" />
</LinearLayout>

轉(zhuǎn)自:https://blog.csdn.net/demonliuhui/article/details/82532078

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痢士,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子茂装,更是在濱河造成了極大的恐慌怠蹂,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件训唱,死亡現(xiàn)場離奇詭異褥蚯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)况增,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門赞庶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人澳骤,你說我怎么就攤上這事歧强。” “怎么了为肮?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵摊册,是天一觀的道長。 經(jīng)常有香客問我颊艳,道長茅特,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任棋枕,我火速辦了婚禮白修,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘重斑。我一直安慰自己兵睛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著祖很,像睡著了一般笛丙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上假颇,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天胚鸯,我揣著相機(jī)與錄音,去河邊找鬼拆融。 笑死蠢琳,一個胖子當(dāng)著我的面吹牛啊终,可吹牛的內(nèi)容都是我干的镜豹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蓝牲,長吁一口氣:“原來是場噩夢啊……” “哼趟脂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起例衍,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤昔期,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后佛玄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硼一,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年梦抢,在試婚紗的時候發(fā)現(xiàn)自己被綠了般贼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡奥吩,死狀恐怖哼蛆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情霞赫,我是刑警寧澤腮介,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站端衰,受9級特大地震影響叠洗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旅东,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一灭抑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧玉锌,春花似錦名挥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽榄融。三九已至,卻和暖如春救湖,著一層夾襖步出監(jiān)牢的瞬間愧杯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工鞋既, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留力九,地道東北人。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓邑闺,卻偏偏與公主長得像跌前,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子陡舅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評論 2 359

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