[in-depth rxbus]: Supports sticky events

Source: Internet
Author: User
Tags exception handling thread eventbus

Rxbus, Eventbus because of the decoupling is too thorough, misuse, the project maintainability will be lower; some simple scenarios recommend using callbacks, subject instead of event bus.

The actual use of the scene, if Rxbus,eventbus two, I prefer to use Eventbus, Rxjava focus on workflow, Eventbus focus on the event bus, clearer responsibilities

For a while, a few months ago, I wrote a simple Rxbus article: Implement the event bus with Rxjava.

In the real world, you will find that Rxbus still has some problems. You need Rxbus support for sticky features. You will find that after you subscribe to an event, when the event is subsequently received, an exception occurs during processing, and you may find that subsequent events are not received.

I will be divided into 2 articles to give their proposal, this article describes how to implement Sticky, and another introduction to the Rxbus in the exception handling scheme:
Deep rxbus:[exception Handling] What is the sticky event.

In Android development, the sticky event is a special type of event that the event consumer registers only after the event has been published. There is an example of this in Android, the sticky broadcast, the sticky broadcast. Normally, if the sender sends a broadcast and the receiver registers his receiver after the broadcast is sent, the receiver cannot receive the broadcast, and the Stickybroadcast is introduced for Android. The broadcast (Intent) that was just sent is saved after the broadcast is sent, so that when the receiver registers receiver, it can receive a broadcast that has just been released. This allows us to deal with events in advance so that customers can be delivered to consumers. Subject

We used the publishsubject when we implemented the simple Rxbus, in fact Rxjava provided to the developer 4 kinds of Subject:
Publishsubject,behaviorsubject, Behaviorsubject,asyncsubject. Publishsubject only sends data to observers after the point in time at which subscribers subscribe.

When a subscriber subscribes, Behaviorsubject sends its most recently sent data (it sends a default value if no data is received at this time).

Replaysubject when Subscribers subscribe, all data is sent to subscribers, regardless of when they are subscribed.

Asyncsubject only after the original observable event sequence is completed, the last data is sent, and if a subscriber continues to subscribe to the subject, the last value can be received directly. Subject

From the above picture, it seems that behaviorsubject and replaysubject have sticky characteristics. Behaviorsubject Solutions

Behaviorsubject seems to fit perfectly with the definition of sticky, but you have found that it can only save the most recent event.

There is a scenario where subscriber a subscribes to EVENT1, subscriber B subscribes to Event2, and at this point the Behaviorsubject event queue is [..., Event2, Event1] When subscribers subscribe, because the most recent event is saved: Event1, So subscriber B is not receiving Event2.

The solution is:
Each event type creates a corresponding behaviorsubject, which means that the resource overhead is large and the sticky event bus and the normal Rxbus event bus cannot be shared, i.e. normal events and sticky events are independent , because the normal event is based on Publishsubject , and temporarily abandons the scheme. Replaysubject Solutions

Replaysubject can save all data events that have been sent.

Because all the data events are saved, no matter what type of event, we simply filter the type and let it send the nearest event to satisfy the sticky event. However, it is difficult to get the closest corresponding event, because the best-fit operator Takelast () only sends the last data event at the end of the subscription event (that is: oncompleted ()), and our rxbus should normally try to avoid the end of its subscription event. (I'm not able to find the right operator, if you know, please tell me)

So Behaviorsubject is also more difficult to achieve sticky characteristics.

and, whether Behaviorsubject or replaysubject, they have a tricky problem: the data between the eventbus they implement and the normal Rxbus (based on Publishsubject) are independent of each other.

Summary: Behaviorsubject and behaviorsubject are not naturally suitable for sticky events ... using map to implement sticky

This approach is based on the original Publishsubject implementation of the Rxbus, using the concurrenthashmap< event type, Event > Save the recent events of each event, not only to achieve sticky characteristics, most importantly can be shared with ordinary Rxbus event data, not independent .

Because our Rxbus is based on Publishsubject, and Rxjava has 4 subject, and Behaviorsubject and Replaysubject appear to conform to sticky features, we might drill this niu Jiao Jian , it is taken for granted that implementing sticky needs to be done through other types of subject .... (Well, I got into it ...)

The idea of this scheme is based on the realization of Eventbus, the following is the approximate process: Map initialization:

   Private final map<class<?>, object> Mstickyeventmap;

    Public Rxbus () {
        mBus = new serializedsubject<> (Publishsubject.create ());
        Mstickyeventmap = new concurrenthashmap<> ();
    }

The Concurrenthashmap is a thread-safe HashMap with stripping lock (split lock), which is much more efficient than Hashtable. In our Poststicky (Event), it is stored in map:

public void Poststicky (Object event) {
     synchronized (mstickyeventmap) {
         mstickyeventmap.put (Event.getclass () , event);
     } 
     Post (event); 
}
At the time of subscription toobservablesticky (class<t> eventtype), first look for the type of event from the map, if not, then no sticky event to send, Subscribe directly to Subject (at this point as the Observer observable), and if so, indicate that there are sticky events to send, subscribe to merge (Subject and sticky events).
  Public <T> observable<t> toobservablesticky (final class<t> eventtype) {
        synchronized ( Mstickyeventmap) {
            observable<t> Observable = Mbus.oftype (eventtype);
            Final Object event = Mstickyeventmap.get (EventType);

            if (event! = null) {
                return Observable.mergewith (Observable.create (new observable.onsubscribe<t> () {
                    @ Override public
                    void Call (SUBSCRIBER<? Super T> Subscriber) {
                        Subscriber.onnext (Eventtype.cast (event)) ;
                    }
                }));
            } else {
                return observable;}}
    }

Merge operator: You can merge multiple observables as if they were a single observable.

In this way, the core function of the sticky is completed, using the same as the normal Rxbus, through the Poststicky () Send events, Toobservablesticky () subscription events.

In addition, I also provided getstickyevent (class<t> eventtype), removestickyevent (class<t> eventtype), Removeallstickyevents () method for locating, removing events of the corresponding event type, and removing all sticky events. the important thing

When using the sticky attribute, when a sticky event is not required, it is removed by removestickyevent (class<t> EventType), The safest practice is to removeallstickyevents () in the OnDestroy of the main activity.
Because our Rxbus is a single static object, and then exit the app normally, the object will still exist in the JVM, unless the process is killed, so that the data in the Stickymap is still there, in order to avoid the problem, you need to clean up the stickymap when the app exits.

The main activity (usually the bottom of the stack activity)
@Override
protected void OnDestroy () {
    Super.ondestroy ();
    Remove all sticky events
    rxbus.getdefault (). removeallstickyevents ();
}
Full Code

The following is the full Rxbus code that supports sticky:

/** * Publishsubject: Only the data from the original observable after the point at which the subscription occurred is emitted to the observer * <p> * Created by Yokeyword on 2015/6/17.
    */public class Rxbus {private static volatile rxbus mdefaultinstance;

    Private final Subject<object, object> MBus;

    Private final map<class<?>, object> Mstickyeventmap;
        Public Rxbus () {mBus = new serializedsubject<> (Publishsubject.create ());
    Mstickyeventmap = new concurrenthashmap<> (); 
                } public static Rxbus Getdefault () {if (mdefaultinstance = = null) {synchronized (Rxbus.class) {
                if (mdefaultinstance = = null) {mdefaultinstance = new Rxbus ();
    }}} return mdefaultinstance;
    }/** * Send event */public void post (Object event) {Mbus.onnext (event); /** * Returns the observed person for a specific type (EventType) based on the EventType type passed in */public <T> observable<t> toobservable ( Class&lT
    T> eventtype) {return mbus.oftype (EventType);
    }/** * Determine if there is a subscriber */public boolean hasobservers () {return mbus.hasobservers ();
    } public void Reset () {mdefaultinstance = null;
        }/** * Stciky related *//** * Send a new sticky event */public void Poststicky (Object event) {
        Synchronized (Mstickyeventmap) {mstickyeventmap.put (Event.getclass (), event);
    } post (event); /** * Returns the viewer of a specific type (EventType) based on the EventType type passed */public <T> observable<t> Toobservables Ticky (Final class<t> EventType) {synchronized (mstickyeventmap) {observable<t> observabl
            E = Mbus.oftype (EventType);

            Final Object event = Mstickyeventmap.get (EventType); if (event! = null) {return Observable.mergewith (observable.create (New observable.onsubscribe<t> ()
    {@Override                public void call (SUBSCRIBER&LT;? Super T> Subscriber) {Subscriber.onnext (event
                    Type.cast (event));
            }
                }));
            } else {return observable; }}}/** * Get sticky event based on EventType */public <T> T getstickyevent (class<t> event
        Type) {synchronized (Mstickyeventmap) {return eventtype.cast (Mstickyeventmap.get (EventType)); }}/** * Removes the sticky event for the specified EventType */public <T> T removestickyevent (class<t> Eventtyp
        e) {synchronized (Mstickyeventmap) {return eventtype.cast (Mstickyeventmap.remove (EventType)); }}/** * Remove all sticky events */public void removeallstickyevents () {synchronized (Mstickyev
        Entmap) {mstickyeventmap.clear ();
 }
    }
}

Although the use of thread-safe concurrenthashmap, but still a lot of use of synchronized, you can find the lock is Mstickyeventmap object, which is to ensure that the read, write, check, delete synchronization, that is, read can not write, write can not read ... finally

Attach a Demo: Provides examples of sample exception handling using the Sticky feature: allow it to receive subsequent events correctly after an exception occurs.

Reference source, Portal Demo reference:

reactivex:http://reactivex.io/
Eventbus:https://github.com/greenrobot/eventbus


Transferred from: https://www.jianshu.com/p/71ab00a2677b

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.