Eventbus of Fast Android development Series communication articles

Source: Internet
Author: User
Tags eventbus

Overview and Basic concepts

The **eventbus** is an Android-optimized publish/subscribe messaging bus that simplifies communication between components within an application and between components and background threads. such as requesting the network, and so on when the network returns through the handler or broadcast notification UI, two fragment between the need for listener communication, these requirements can be achieved through **eventbus**.

As a message bus, there are three main elements:

    • Event: Events
    • Subscriber: Event subscribers, receiving specific events
    • Publisher: Event Publisher to notify Subscriber that an event has occurred
Event

**event** can be any type of object.

Subscriber

In Eventbus, you use conventions to specify event subscribers for ease of use. That is, all event subscriptions are functions that begin with onevent, specifically, the name of the function is Onevent,oneventmainthread,oneventbackgroundthread,oneventasync four, This is related to Threadmode, and later.

Publisher

You can send an event anywhere on any thread, call the Eventbus ' post (object) method directly, and instantiate the Eventbus object yourself, but generally use the default singleton as well: ' Eventbus.getdefault () ', The function that subscribes to the corresponding type of event is automatically invoked based on the type of the post function parameter.

Threadmode

As I said earlier, the name of the Subscriber function can only be those 4, because each event subscription function is associated with a ' threadmode ', and Threadmode specifies the function that will be called. The following four Threadmode are available:

    • Postthread: The handling of events in the same process as the sending of events, so the event processing time should not be too long, otherwise affect the sending thread of the event, and this thread may be the UI thread. The corresponding function name is onevent.
    • Mainthread: The handling of the event is performed in the UI thread. Event processing time can not be too long, this needless to say, long will be ANR, the corresponding function name is Oneventmainthread.
    • Backgroundthread: The handling of the event is executed in a background thread, the corresponding function name is Oneventbackgroundthread, although the name is Backgroundthread, event processing is in the background thread, However, the event processing time should not be too long, because if the thread that sends the event is a background thread, the event is executed directly, if the current thread is the UI thread, the event is added to a queue, the events are processed sequentially by a single thread, and if an event is too long, it blocks the dispatch or processing of subsequent events.
    • Async: Event handling executes in a separate thread, primarily for time-consuming operations in a background thread, each of which turns on one thread (the cable pool), but it is best to limit the number of threads.

Depending on the function name of the event subscription, a different threadmode is used, and the subscriber simply names the function Oneventmainthread if the data is downloaded in the background line loads to be displayed in the UI thread.

Simple to use

The basic use step is the following 4 steps, click this link to see examples and introduction.

    1. Define the event type:
      ' public class MyEvent {} '
    2. Define Event handling methods:
      ' public void Oneventmainthread '
    3. Registered Subscribers:
      ' Eventbus.getdefault (). Register (This) '
    4. Send event:
      ' Eventbus.getdefault (). Post (New MyEvent ()) '
Realize

**eventbus** the use of the method is very simple, but with a thing, if you do not understand its implementation of the heart is always no end, in case of problems do not know, so or to study its implementation, definitely read the fucking Code. In fact, the main is ' Eventbus ' this class, in looking at code need to understand a few concepts and members, understand these after implementation is very good understanding.

    • A parameter in the Eventtype:onevent\* function that represents the type of event
    • Subscriber: The subscription source, which is the object registered by the register, contains the onevent\* function in the object
    • Subscribmethod: ' Subscriber ' within a particular onevent\* method, an internal member that contains a ' method ' type method member represents this onevent\* approach, a ' threadmode ' The member Threadmode represents the processing thread of the event, and a EventType member of the ' class<?> ' type represents the type ' eventtype ' of the event.
    • Subscription, which represents a subscription object that contains the feed ' subscriber ', a specific method in the feed ' subscribmethod ', the priority of this subscription ' priopity '


After understanding the above concepts, we can see several important members of ' Eventbus '.

EventType, List<subscription> the mapping between events to subscribed objects private final map<class<?> copyonwritearraylist <Subscription>> subscriptionsbyeventtype;//subscriber-list<eventtype> The mapping of all event types subscribed to by the source to which it subscribes private final map<object, list<class<?>>> typesbysubscriber;//stickevent events, You will see the private final map<class<?> later, object> stickyevents;//EventType, list<? Extends Eventtype>, the mapping of the event to its parent event list. That is, all the parent classes of a class are cached private static final map<class<?>, list<class<?>>> eventtypescache = new HashMap <class<?>, list<class<?>>> ();
Register Event: Register

Through the ' Eventbus.getdefault (). Register ' method you can subscribe to the event by registering with ' Eventbus ', ' register ' has many overloaded forms, but most of them are labeled ' Deprecated ', so it is still not good, Earlier said that the event processing methods are beginning with *onevent*, in fact, can be modified by the Register method, but the corresponding method was discarded, or do not use, with the default *onevent*, in addition to the obsolete register method, there are the following 4 **public* * the ' register ' method

public void Register (Object subscriber) {    Register (subscriber, Defaultmethodname, false, 0);} public void Register (Object subscriber, Int. priority) {    Register (subscriber, Defaultmethodname, false, priority);} public void Registersticky (Object subscriber) {    Register (subscriber, Defaultmethodname, True, 0);} public void Registersticky (Object subscriber, Int. priority) {    Register (subscriber, Defaultmethodname, True, priority);}

As you can see, these 4 methods all call the same method:

Private synchronized void Register (Object subscriber, String methodName, boolean sticky, int priority) {    list<subs cribermethod> subscribermethods = Subscribermethodfinder.findsubscribermethods (Subscriber.getClass (), MethodName);    for (Subscribermethod subscribermethod:subscribermethods) {        Subscribe (subscriber, Subscribermethod, sticky, priority);}    }

The first parameter is the feed, the second parameter is used to specify the method name convention, the default is *onevent* start, said the default is actually can be modified by the parameters, but said before, the method has been discarded, it is best not to use. The third parameter indicates whether it is *sticky event*, and the 4th parameter is the priority, which is the two later.

In the above method, a class called ' Subscribermethodfinder ' was used, and a ' subscribermethod ' list was found by its ' findsubscribermethods ' method, which was previously known as ' Subscribermethod ' represents a onevent\* method within Subcriber, which can be seen as ' Subscribermethodfinder ' The function of a class is to find all methods in subscriber that begin with MethodName (that is, the default onevent), and each found method is represented as a ' Subscribermethod ' object.

' Subscribermethodfinder ' is no longer analyzed, but there are two points to know:

    1. All Event Handling Methods * * must be ' public void ' type *, and only one parameter represents *eventtype*.
    2. ' Findsubscribermethods ' not only looks for event handling methods within *subscriber*, but also finds event handling methods in all base classes in its inheritance system * *.

Once all the event-handling methods in *subscriber* are found, the ' subscribe ' method is registered for each method found (represented as the ' Subscribermethod ' object). The ' subscribe ' method has done three things:

    1. The ' subscribtion ' object is stored in ' subscriptionsbyeventtype ' according to the *eventtype* type in ' Subscribermethod '. Establish a mapping of *eventtype* to *subscription*, where each event can have multiple subscribers.
    2. The ' eventtype ' is stored in ' typesbysubscriber ' according to ' subscriber ', creating a map of *subscriber* to *eventtype*, and each Subscriber can subscribe to multiple events.
    3. If it is a *sticky* type of subscriber, send it the last saved event (if any) directly to it.

With the *subscriber* to *eventtype* mapping, we can easily make a subscriber cancel the receive event, through the *eventtype* to the *sucscribtion* map, It is easy to send the appropriate event to each of its subscribers.

Post Event

A direct call to ' Eventbus.getdefault (). Post (event) can send events that can be sent to subscribers to the corresponding event based on the type of event.

public void Post (Object event) {    postingthreadstate postingstate = Currentpostingthreadstate.get ();    list<object> eventqueue = postingstate.eventqueue;    Eventqueue.add (event);    if (postingstate.isposting) {        return;    } else {        postingstate.ismainthread = looper.getmainlooper () = = Looper.mylooper ();        Postingstate.isposting = true;        if (postingstate.canceled) {            throw new eventbusexception ("Internal error. Abort state is not reset ");        try {while            (!eventqueue.isempty ()) {                postsingleevent (eventqueue.remove (0), postingstate);            }        } finally {            postingstate.isposting = false;            Postingstate.ismainthread = false;}}}    

You can see that the "Postingthreadstate" object is used within the post, and is ' ThreadLocal ', to see the definition of ' postingthreadstate ':

Final Static class Postingthreadstate {    list<object> eventqueue = new arraylist<object> ();    Boolean isposting;    Boolean ismainthread;    Subscription Subscription;    Object event;    Boolean canceled;}

The main thing is that there is a member ' EventQueue ', because it is threadlocal, so the result is that each thread has a ' postingthreadstate ' object, an object that has a queue of events inside, and a member ' isposting ' Indicates whether an event is currently being dispatched, and when the sending event starts, the events in the queue are sent out, and if the event is being dispatched, post directly joins the event to the queue, and a member ' Ismainthread ', which is used when the event is actually distributed, in the ' Postsingleevent ' will be used.

private void Postsingleevent (Object event, Postingthreadstate postingstate) throws Error {class<? extends Object&gt ;    EventClass = Event.getclass (); list<class<?>> eventtypes = findeventtypes (EventClass);    1 Boolean subscriptionfound = false;    int counttypes = Eventtypes.size ();        for (int h = 0; h < counttypes; h++) {//2 class<?> clazz = Eventtypes.get (h);        copyonwritearraylist<subscription> subscriptions;        Synchronized (this) {subscriptions = Subscriptionsbyeventtype.get (clazz);  } if (subscriptions! = null &&!subscriptions.isempty ()) {//3 for (Subscription Subscription:                Subscriptions) {postingstate.event = event;                Postingstate.subscription = subscription;                Boolean aborted = false; try {posttosubscription (subscription, event, postingstate.ismainthread);//4 Abort ed = Postingstate.canceled;                    } finally {postingstate.event = null;                    Postingstate.subscription = null;                postingstate.canceled = false;                } if (aborted) {break;        }} Subscriptionfound = true;        }} if (!subscriptionfound) {log.d (TAG, "No subscribers registered for event" + EventClass); if (EventClass! = Nosubscriberevent.class && EventClass! = Subscriberexceptionevent.class) {post (new N        Osubscriberevent (this, event)); }    }}

Take a look at the ' postsingleevent ' function, first of all the 1th, call the ' findeventtypes ' function, the code is not, the application of this function is to put the class object, the implementation of the interface and the parent class object to a list to return.

Next, take the second step, iterate through the list in the first step, and perform a third operation on each class object in the list (that is, the event type), which is where all subscribers to the event type are found to send the event. As you can see, * * When we post an event, the parent event of the event (the event class's parent Class) is also post, so if an event subscriber receives an event of type object, it can receive all the events * *.

You can also see that the actual event is sent via the ' posttosubscription ' in the fourth step, and the event and subscribers are credited with ' Postingstate ' before sending. and see ' posttosubscription '

private void Posttosubscription (Subscription Subscription, Object event, Boolean ismainthread) {    switch ( Subscription.subscriberMethod.threadMode) {case    Postthread:        invokesubscriber (subscription, event);        break;    Case Mainthread:        if (ismainthread) {            invokesubscriber (subscription, event);        } else {            Mainthreadposter.enqueue (subscription, event);        }        break;    Case Backgroundthread:        if (ismainthread) {            backgroundposter.enqueue (subscription, event);        } else {            Invokesubscriber (subscription, event);        }        break;    Case Async:        asyncposter.enqueue (subscription, event);        break;    Default:        throw new IllegalStateException ("Unknown thread mode:" + Subscription.subscriberMethod.threadMode);}    }

The ' Threadmode ' is used here:

    • If it is postthread, direct execution
    • If it is mainthread, judge the current thread, and if it is the UI thread that executes directly, join the ' mainthreadposter ' queue
    • If it is a background thread, if it is currently the UI thread, join the ' backgroundposter ' queue, otherwise execute directly
    • If it is async, join the ' asyncposter ' queue
Backgroundposter
Private final pendingpostqueue queue;public void Enqueue (Subscription Subscription, Object event) {    pendingpost Pendingpost = pendingpost.obtainpendingpost (subscription, event);    Synchronized (this) {        queue.enqueue (pendingpost);        if (!executorrunning) {            executorrunning = true;            EventBus.executorService.execute (this);}}}    

The code is simple, in fact, the event to be sent is encapsulated as a ' pendingpost ' object, ' Pendingpostqueue ' is a queue of ' Pendingpost ' object, when ' Enqueue ' the event is placed in the queue, ' Backgroundposter ' is actually a runnable object, when ' enqueue ', if this Runnable object is not currently executed, it will ' backgroundposter ' into a thread pool in Eventbus, when ' When Backgroundposter ' is executed, the events in the queue are taken out in turn to dispatch. The thread to which ' backgroundposter ' belongs when there is no event for a long time is destroyed, and a new thread is created the next time the post event occurs.

Handlerposter

' Mainthreadposter ' is a ' handlerposter ' object, ' Handlerposter ' inherits from ' Handler ', and the constructor receives a ' Looper ' object when it comes to ' handlerposter ' Enqueue event, the event will be added to the queue like ' backgroundposter ', only if the message is not currently being dispatched

void Enqueue (Subscription Subscription, Object event) {    Pendingpost pendingpost = Pendingpost.obtainpendingpost ( subscription, event);    Synchronized (this) {        queue.enqueue (pendingpost);        if (!handleractive) {            handleractive = true;            if (!sendmessage (Obtainmessage ())) {                throw new eventbusexception ("Could not send Handler message");}}}    

In ' Handlemessage ', the messages in the queue are fetched to the ' Eventbus ' to invoke the event handler directly, and ' handlemessage ' execution thread is the thread that the ' Looper ' belongs to in the constructor, in ' Eventbus ' The structure ' mainthreadposter ' simultaneous comes in mainlooper, so it executes in the UI thread.

Asyncposter

' Asyncposter ' is simple, and each event is added to the thread pool for processing

public void Enqueue (Subscription Subscription, Object event) {    Pendingpost pendingpost = Pendingpost.obtainpendingpost (subscription, event);    Queue.enqueue (pendingpost);    EventBus.executorService.execute (this);}
Stick Event

The stick event handler can be registered through ' registersticky ', before we know that either ' register ' or ' Registersticky ' will call the ' Subscribe ' function at the end of ' Subscribe ' There is a code in this section:

That is, the event type is looked up from ' stickyevents ' to see if there is a corresponding event, and if so, send this event directly to the Subscriber. And when was the event saved, with ' register ' and ' Registersticky ', and ' post ' with a ' poststicky ' function:

if (sticky) {    Object stickyevent;    Synchronized (stickyevents) {        stickyevent = Stickyevents.get (EventType);    }    if (stickyevent! = null) {        //If the Subscriber is trying to abort the event, it would fail (event is not tracked in PO Sting state)        //--Strange corner case, which we don't take care of here.        Posttosubscription (Newsubscription, Stickyevent, looper.getmainlooper () = = Looper.mylooper ());}    }

When an event is sent through ' Poststicky ', the last event of this type of event is cached, and when a subscriber registers with ' Registersticky ', the event that was previously cached is sent directly to it.

Event Precedence Priority

There is a function overload in ' register ' that can specify the priority of the Subscriber, and we know that there is a mapping of event type to list<subscription> in ' Eventbus ', in this mapping, All subscription are sorted by priority, so that when the post event, the higher precedence gets the opportunity to handle the event.

One application of priority ratione materiae, high-priority event handlers can finally pass the event, through the ' canceleventdelivery ' method, but one thing to note, ' The Threadmode of this event must be Postthread ', And only finally it is in the handling of events.

# disadvantages
Cannot communicate between processes, if there are multiple processes in an application, there is no way.

# Considerations and Points

    • The same onevent function cannot be registered two times, so it cannot be registered in a class and is also registered in the parent class.
    • When an event is post, the event of the parent class of the event class is also post.
    • Post events with no subscriber processing will post the ' Nosubscriberevent ' event when the call Subscriber fails with the post ' Subscriberexceptionevent ' event.
Other

' Eventbus ' also has a util package, the main function is to be able to execute a runnable through the ' Asyncexecutor ', through the internal Runnableex (can search for abnormal runnable) when runnable throws an exception through the ' Eventbus ' message displays an error dialog box. Not much interest, no analysis

Project home: Https://github.com/greenrobot/EventBus

A very simple demo,activity contains lists and details two fragment,activity load a list at startup, click on the list to update the detail data: Eventbusdemo

Eventbus of Fast Android development Series communication articles

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.