A detailed tutorial on the communication tool Eventbus between Android components

Source: Internet
Author: User
Tags constructor static class eventbus

Overview and Basic concepts

**eventbus** is an Android-optimized Publish/subscribe message bus that simplifies communication between components, components, and background threads within an application. such as the request network, when the network returns through the handler or broadcast notification UI, two fragment need to communicate through the listener, these requirements can be achieved through the **eventbus**.

As a message bus, there are three main elements:

Event: Events
Subscriber: Event Subscriber, receiving a specific event
Publisher: Event Publisher, used to inform subscriber that an event occurred

Event

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

Subscriber

In Eventbus, use Conventions to specify event subscribers to simplify use. That is, all event subscriptions are functions that start with onEvent, specifically, the name of the function is Onevent,oneventmainthread,oneventbackgroundthread,oneventasync four, this and Threadmode about, and later.

Publisher

You can send events anywhere in any thread, call the Eventbus ' post (object) method directly, and instantiate the Eventbus object yourself, but generally use the default single example: ' Eventbus.getdefault () ', The function that subscribes to the corresponding type of event is automatically invoked, depending on the type of the post function argument.

Threadmode

As mentioned earlier, the Subscriber function can only be the name of the 4, because each event subscription function is associated with a ' threadmode ', and Threadmode specifies the function that will be invoked. Has the following four threadmode:

Postthread: The processing of events is in the same process as the sending of events, so the event processing time should not be too long, or it will affect the sending thread of the event, which may be the UI thread. The corresponding function name is onevent.
Mainthread: The processing of events 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: Event processing is performed in a background thread, the corresponding function name is Oneventbackgroundthread, although the name is Backgroundthread, event handling is in the background thread, But the event processing time should not be too long, because if the thread that sent the event is a background thread, the event is executed directly, and if the current thread is a UI thread, the event is added to a queue, which is handled by one thread in turn, and if an event is too long, it blocks the distribution or processing of subsequent events.
Async: Event handling is performed in a separate thread, primarily for time-consuming operations in a background thread, with each event opening a thread (a wired 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 in the background line Chengga to be displayed on the UI thread.

Simple to use





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





To define an event type:


' public class MyEvent {} '


Define Event handling methods:


' public void Oneventmainthread '


Register Subscribers:


' Eventbus.getdefault (). Register (This) '


Send event:


' Eventbus.getdefault (). Post (New MyEvent ()) '





Implement





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





An argument in the eventtype:onevent* function that represents the type of event


Subscriber: The feed, that is, the object that invokes register registration, which contains the onevent* function


Subscribmethod: A particular onevent* method in ' Subscriber ', in which the inner member contains a method member of the ' methods ' type that represents the onevent* approach, a ' threadmode ' The member Threadmode represents the processing thread of the event, and a ' class<?> ' type of EventType member represents the type ' eventtype ' of the event.


Subscription, which represents a subscription object that contains a subscription source ' Subscriber ', a specific method in the feed ' Subscribmethod ', and the priority of this subscription ' priopity '








Once you know these concepts, you can look at several important members of ' Eventbus '.

  code is as follows copy code
//eventtype-> list<subscription>, events to the mapping between the subscription objects
Private final map <class<?>, copyonwritearraylist<subscription>> Subscriptionsbyeventtype;

//subscriber-> List<eventtype>, the mapping of all event types to which the feed is subscribed
private final Map<object, List<class <?>>> Typesbysubscriber;

//Stickevent event, followed by the
private final map<class<?> 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 ' Eventbus ' for the event, ' Register ' There are many kinds of overloaded forms, but most of them are marked ' deprecated ', so it is still not good, said the event processing methods are started with the *onevent*, in fact, can be modified by the Register method, but the corresponding method was abandoned, Or do not use, the default *onevent*, in addition to the obsolete register method, there are the following 4 **public** ' register ' method

  code is as follows copy code
public void Register (Object subscriber) {
    Register (subscriber, Defaultmethodname, false, 0);


public void Register (Object subscriber, int priority) {
    Register (subscriber, Defaultmeth Odname, 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, all 4 methods call the same method:

The code is as follows Copy Code
Private synchronized void Register (Object subscriber, String methodname, boolean sticky, int priority) {
list<subscribermethod> 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 of the Convention, the default is *onevent* start, said the default is actually can be modified by the parameters, but said earlier, the method has been abandoned, it is best not to use. The third parameter indicates whether it is *sticky event*, and the 4th argument is priority, which is later.





In the above method, a class called ' Subscribermethodfinder ' was used, and through its ' findsubscribermethods ' method, a list of ' Subscribermethod ' was found, preceded by a ' Subscribermethod ' represents a onevent* method within the Subcriber, and you can see that the role of the ' Subscribermethodfinder ' class is to find all in subscriber MethodName (that is, the default onevent), each method found is represented as a ' Subscribermethod ' object.





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





All event-handling methods * * must be ' public void ' type * *, and only one parameter represents *eventtype*.


' Findsubscribermethods ' not only looks for event-handling methods within *subscriber*, but also finds event-handling methods in all base classes in its inheritance system * *.





After all the event-handling methods in *subscriber* are found, the ' subscribe ' method registration is invoked for each method found (expressed as ' Subscribermethod ' object). The ' subscribe ' method did three things:





The ' subscribtion ' object is stored in ' subscriptionsbyeventtype ' according to the type of *eventtype* in ' Subscribermethod '. Create *eventtype* to *subscription* mappings, each event can have multiple subscribers.


According to ' Subscriber ' store ' eventtype ' in ' typesbysubscriber ', create *subscriber* to *eventtype* mapping, each Subscriber can subscribe to multiple events.


If it is a subscriber of type *sticky*, send the last saved event directly to it (if any).





By *subscriber* to the *eventtype* mapping, we can conveniently allow a subscriber to cancel the receive event, through *eventtype* to *sucscribtion* mapping, The appropriate event can be easily sent to each of its subscribers.

Post Events

Direct call to ' Eventbus.getdefault (). Post (event) can send events, depending on the type of event can be sent to the appropriate event subscribers.

The code is as follows Copy Code
public void Post (Object event) {


Postingthreadstate postingstate = Currentpostingthreadstate.get ();


list&lt;object&gt; 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 the ' Postingthreadstate ' object in post and the ' ThreadLocal ' to see the definition of ' postingthreadstate ':

  code is as follows copy code
final static Class Postingthreadstate {
    list<object> eventqueue = new arraylist<object> ();
& nbsp;   Boolean isposting;
    Boolean ismainthread;
    Subscription Subscription;
    Object event;
    Boolean canceled;
}


There is mainly a member ' EventQueue ', because it is threadlocal, so the result is that each thread has a ' postingthreadstate ' object, which has a queue of events within it, and a member ' isposting ' means now Whether the event is being distributed, and when the sending event begins, the events in the queue are sent out in turn, and if the event is being distributed, then Post directly adds the event to the queue and returns, and a member ' Ismainthread ', which is used in the actual distribution of the event, in ' Postsingleevent ' will be used.

The code is as follows Copy Code
private void Postsingleevent (Object event, Postingthreadstate postingstate) throws Error {


class&lt;? Extends object&gt; EventClass = Event.getclass ();


list&lt;class&lt;?&gt;&gt; eventtypes = findeventtypes (EventClass); 1


Boolean subscriptionfound = false;


int counttypes = Eventtypes.size ();


for (int h = 0; h &lt; counttypes h++) {//2


Class&lt;?&gt; clazz = Eventtypes.get (h);


copyonwritearraylist&lt;subscription&gt; subscriptions;


Synchronized (this) {


Subscriptions = Subscriptionsbyeventtype.get (clazz);


}


if (subscriptions!= null &amp;&amp;!subscriptions.isempty ()) {//3


for (Subscription subscription:subscriptions) {


Postingstate.event = event;


Postingstate.subscription = subscription;


Boolean aborted = false;


try {


Posttosubscription (subscription, event, Postingstate.ismainthread); 4


aborted = 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 &amp;&amp; eventclass!= subscriberexceptionevent.class) {


Post (this, event) (nosubscriberevent);


}


}


}


Look at the ' postsingleevent ' this function, first look at the 1th, called the ' findeventtypes ' This function, the code does not post, the application of this function is that the class object of this class, implements the interface and the parent class object to save in a list of the return.

Next step, iterate through the list in the first step, perform a third step on each class object in the list (that is, the event type), where all the Subscribers to the event type are found to send the event. As you can see, * * When we post an event, the parent of the event (the event of the parent class of the event class) is also posted, so if an event subscriber receives an object of type event, it can receive all the event * *.

You can also see that the event is actually sent through the ' posttosubscription ' in step fourth, and the event and Subscriber are deposited in ' postingstate ' before sending. And look at ' posttosubscription '

The code is as follows Copy Code
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);


}


}

Here's where the ' Threadmode ' is used:

If it's postthread, execute it directly.
If it is mainthread, determine the current thread, if it is the UI thread to execute directly, otherwise join the ' mainthreadposter ' queue
If it is a background thread, if it is currently a UI thread, join the ' backgroundposter ' queue, or execute directly
If it's async, join the ' asyncposter ' queue

Backgroundposter

  code is as follows copy code
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 simpler, in fact, the events to be sent are encapsulated as ' pendingpost ' objects, ' pendingpostqueue ' is a queue of ' Pendingpost ' objects, and when ' Enqueue ' the event is placed in the queue, ' Backgroundposter ' is actually a runnable object, when ' Enqueue ', if the Runnable object is not currently executed, ' Backgroundposter ' is added to a thread pool in the Eventbus, when ' When Backgroundposter ' is executed, the events in the queue are then sorted out for distribution. The thread to which the ' Backgroundposter ' belongs is destroyed when there is no event for a long time, and a new thread is created the next time the event is post.

Handlerposter

' Mainthreadposter ' is a ' handlerposter ' object, ' Handlerposter ' inherits from ' Handler ', the constructor receives a ' Looper ' object, and when to ' Handlerposter ' Enqueue event, the event is added to the queue like ' Backgroundposter ', except that if the message is not currently being distributed, send it to itself

The code is as follows Copy Code
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 message in the queue is fetched to the ' eventbus ' directly to invoke the event handler, and the thread that executes the ' handlemessage ' is the thread that is the ' looper ' that is passed in the constructor in ' Eventbus ' Constructs ' mainthreadposter ' newsletters in is mainlooper, so it is executed in the UI thread.

Asyncposter

' Asyncposter ' is simple, adding each event to the thread pool to process

The code is as follows Copy Code
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 ', as we know before, either ' register ' or ' Registersticky ' will call the ' Subscribe ' function in ' Subscribe ' There is such a piece of code:

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

The code is as follows Copy Code
if (sticky) {
Object stickyevent;
Synchronized (stickyevents) {
Stickyevent = Stickyevents.get (EventType);
}
if (stickyevent!= null) {
If the Subscriber is trying to abort the event, it'll fail (event isn't tracked in posting state)
--> Strange Corner case, which we don ' t take care of.
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 previously cached event is sent directly to it.

A function overload of the

event priority Priority

' register ' has one that can specify the subscriber's priority, and we know that there is an event type in ' Eventbus ' to list< Subscription> mapping, in which all Subscription are sorted by priority, so that when the post event is high, the priority will be given the opportunity to handle the event first. An application of the

priority is that a High-priority event handler can finally pass through the ' canceleventdelivery ' method, but one thing to note is that ' the Threadmode of this event must be Postthread ', And can only finally be the event it is dealing with.

# Disadvantage
cannot communicate between processes, if there are multiple processes within an application there is no way to do it

# Notes and points

    the same onevent function cannot be registered two times, Therefore, you cannot register in a class and also register
    in the parent class when an event is post, the event of the parent class of the event class is also posted.
    Post events will post ' nosubscriberevent ' events without subscriber processing, post ' when the call subscriber fails ' Subscriberexceptionevent ' event. There is also a util package in the

other

' Eventbus ', which is used to perform a runnable through ' asyncexecutor ' through the internal Runnableex (you can search for an exception runnable) When Runnable throws an exception, the error dialog box is displayed via ' Eventbus ' message. Not much interest, no analysis

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

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

Related Article

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.