Build your own EventBus based on RxJava2

Keywords: Android

Preface

Rxbus is also unavoidable because of the recent learning of RxJava2, but there are still great changes from RxJava1 to RxJava2. For example, in 2.x, Observable does not support backpressure, and a new Flowable will be used to support backpressure. Consumer and BiConsumer have replaced Action1 and Action2, Function has replaced Func1, and BiFunction has replaced Func 2.N. And they all add throws Exception, which means that Mom no longer has to worry about trying-catch when we do something. So our previous RxBus based on Rxjava1 needs to be upgraded.

RxBus Version 1

For RxJava 1.x.x, I believe that everyone is familiar with it, and RxBus is not a word. Here is RxJava I used in RxJava 1 version, with detailed comments in the code. There's not much to say here!

  • RxBus1
public class RxBus {

//    private static volatile RxBus mInstance;
    private SerializedSubject<Object, Object> mSubject;
    private HashMap<String, CompositeSubscription> mSubscriptionMap;

    /**
     *
     * 1,Subject It also acts as Observer and Observable. Subject is non-thread-safe. To avoid this problem,
     * Subject needs to be converted to a Serialized Subject, and thread-insecure PublishSubject is wrapped in the class as thread-safe Subject.
     * 2,PublishSubject Data from the original Observable will only be sent to the observer after the time point at which the subscription occurs.
     *
     */
    public RxBus() {
        mSubject = new SerializedSubject<>(PublishSubject.create());
    }

    // Here we use Dagger to handle singletons
    /*
    private RxBus() {
        mSubject = new SerializedSubject<>(PublishSubject.create());
    }

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

    /**
     * Send events
     *
     * @param o
     */
    public void post(Object o) {
        mSubject.onNext(o);
    }

    /**
     * Returns an Observable instance of the specified type
     * 1,ofType The operator emits only the specified type of data, and inside it is filter+cast
     * @param type
     * @param <T>
     * @return
     */
    public <T> Observable<T> toObservable(final Class<T> type) {
        return mSubject.ofType(type);
    }

    /**
     * Is there an observer subscription?
     *
     * @return
     */
    public boolean hasObservers() {
        return mSubject.hasObservers();
    }

    /**
     * A default subscription method
     *
     * @param type
     * @param next
     * @param error
     * @param <T>
     * @return
     */
    public <T> Subscription doSubscribe(Class<T> type, Action1<T> next, Action1<Throwable> error) {
        return toObservable(type)
                // Add back pressure treatment, otherwise there will be abnormalities in some places. For back pressure reference here: https://gold.xitu.io/post/582d413c8ac24700619cceed
                .onBackpressureBuffer()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(next, error);

    }

   /**
     * Save subscription after subscription
     * @param o
     * @param subscription
     */
    public void addSubscription(Object o, Subscription subscription) {
        if (mSubscriptionMap == null) {
            mSubscriptionMap = new HashMap<>();
        }
        String key = o.getClass().getName();
        if (mSubscriptionMap.get(key) != null) {
            mSubscriptionMap.get(key).add(subscription);
        } else {
//            Represents a set of subscriptions, subscribing unsubscribed together
            CompositeSubscription compositeSubscription = new CompositeSubscription();
            compositeSubscription.add(subscription);
            mSubscriptionMap.put(key, compositeSubscription);
        }
    }
    /**
     * unsubscribe
     * @param o
     */
    public void unSubscribe(Object o) {
        if (mSubscriptionMap == null) {
            return;
        }
        String key = o.getClass().getName();
        if (!mSubscriptionMap.containsKey(key)){
            return;
        }
        if (mSubscriptionMap.get(key) != null) {
            mSubscriptionMap.get(key).unsubscribe();
        }
        mSubscriptionMap.remove(key);
    }
}

RxBus Version 2

Before that, let's familiarize ourselves with the principles of EventBus and RxJava. Here's just a brief chat:
EventBus
EventBus is an efficient publish/subscribe event bus mechanism under Android. It is a publish/subscribe design pattern (Publish/Subsribe), or an observer design pattern.
RxJava
The asynchronous implementation of RxJava is implemented through an extended observer pattern. RxJava has four basic concepts: Observable, Observer, subscribe and event. Observable and Observer implement the subscribe relationship through subscribe() method, so that Observable can send out events to notify Observer when needed.
Understanding what the observer model is, we can better transform RxBbus1 into the RxBus2 we need.

  • RxBus2
    Looking through the Rxjava2 documentation, we know that there is no Serialized Subject class in RxJava2. We can call the toSerialized() method to wrap and serialize the Subject to make it thread-safe. Because Rxjava2 uses Flowable to support backpressure, we can convert it into a Flowable instance with backpressure. Basically, that's the difference between bus1 and bus2!
public class RxBus {
    private HashMap<String, CompositeDisposable> mSubscriptionMap;
    private static volatile RxBus mRxBus;
    private final Subject<Object> mSubject;
    //Single column mode
    public static RxBus getIntanceBus(){
        if (mRxBus==null){
            synchronized (RxBus.class){
                if(mRxBus==null){
                    mRxBus = new RxBus();
                }
            }
        }
        return mRxBus;
    }
    public RxBus(){
         mSubject = PublishSubject.create().toSerialized();
    }

    public void post(Object o){
        mSubject.onNext(o);
    }
    /**
     * Returns a Flowable instance with backpressure of the specified type
     *
     * @param <T>
     * @param type
     * @return
     */
    public <T>Flowable<T> getObservable(Class<T> type){
        return mSubject.toFlowable(BackpressureStrategy.BUFFER)
                .ofType(type);
    }
    /**
     * A default subscription method
     *
     * @param <T>
     * @param type
     * @param next
     * @param error
     * @return
     */
    public <T> Disposable doSubscribe(Class<T> type, Consumer<T> next, Consumer<Throwable> error){
        return getObservable(type)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(next,error);
    }
    /**
     * Is there an observer subscription?
     *
     * @return
     */
    public boolean hasObservers() {
        return mSubject.hasObservers();
    }
    /**
     * disposable after saving subscription
     * @param o
     * @param disposable
     */
    public void addSubscription(Object o, Disposable disposable) {
        if (mSubscriptionMap == null) {
            mSubscriptionMap = new HashMap<>();
        }
        String key = o.getClass().getName();
        if (mSubscriptionMap.get(key) != null) {
            mSubscriptionMap.get(key).add(disposable);
        } else {
            //One-time containers can hold multiple containers and provide additions and removals.
            CompositeDisposable disposables = new CompositeDisposable();
            disposables.add(disposable);
            mSubscriptionMap.put(key, disposables);
        }
    }

    /**
     * unsubscribe
     * @param o
     */
    public void unSubscribe(Object o) {
        if (mSubscriptionMap == null) {
            return;
        }

        String key = o.getClass().getName();
        if (!mSubscriptionMap.containsKey(key)){
            return;
        }
        if (mSubscriptionMap.get(key) != null) {
            mSubscriptionMap.get(key).dispose();
        }

        mSubscriptionMap.remove(key);
    }
}
  • Use

Send events

RxBus rxBus = RxBus.getIntanceBus();
//Send events
rxBus.post(new RxBusMessage("1"));
rxBus.post(new RxBusMessage("2"));

Acceptance of events

private void initRxBus() {
        rxBus = RxBus.getIntanceBus();
        registerRxBus(RxBusMessage.class, new Consumer<RxBusMessage>() {
            @Override
            public void accept(@NonNull RxBusMessage rxBusMessage) throws Exception {
             //Processing according to event type
                if(TextUtils.equals(rxBusMessage.getMessage(),"1")){
                    mTvRebus.setText(rxBusMessage.getMessage());
                }else if(TextUtils.equals(rxBusMessage.getMessage(),"2")){
                    rx2.setText(rxBusMessage.getMessage());
                }
            }
        });
    }

//register
    public <T> void registerRxBus(Class<T> eventType, Consumer<T> action) {
        Disposable disposable = rxBus.doSubscribe(eventType, action, new Consumer<Throwable>() {
            @Override
            public void accept(@NonNull Throwable throwable) throws Exception {
                Log.e("NewsMainPresenter", throwable.toString());
            }
        });
        rxBus.addSubscription(this,disposable);
    }

Destruction incidents

 public void unregisterRxBus() {
        rxBus.unSubscribe(this);
    }
@Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterRxBus();
    }

Effect

Last

Please correct what is wrong! Let's make progress together!

A Little White on the Technological Road

Posted by SamLiu on Wed, 12 Jun 2019 15:02:56 -0700