1. Introduction

EventBus is an event publish-subscribe bus framework for Android, developed by GreenRobot. The Gihub address is: EventBus. It simplifies the complexity of communication between components within an application, especially between fragments, and avoids the inconvenience caused by using broadcast communication.


2. The Subscribe annotation

Since 3.0, methods that Subscribe to events use the Subscribe annotation instead of the method name, as shown below

@Subscribe
public void testEventBus(Object obj){... }Copy the code

Look at the note

@Documented
@Retention(RetentionPolicy.RUNTIME) // Annotations are not only saved to the class file, but still exist after the JVM loads the class file
@Target({ElementType.METHOD})  // function on method
public @interface Subscribe {

    // Specify the thread schema in which the event subscription method is posted
    ThreadMode threadMode(a) default ThreadMode.POSTING;

    // Whether sticky events are supported
    boolean sticky(a) default false;

    // Priority. If a priority is specified, the method with the highest priority receives the same event first.
    int priority(a) default 0;
}
Copy the code

ThreadMode can specify the following modes:

  1. Threadmode. POSTING: As a default thread schema, POSTING processes events in the corresponding thread.
  2. Threadmode. MAIN: If an event is sent on the MAIN thread (UI thread), the event is handled directly on the MAIN thread; If an event is sent in a child thread, it is first queued and then switched to the main thread by Handler, which processes the event in turn.
  3. Threadmode. MAIN_ORDERED: Regardless of which thread sent the event, the event is enqueued and then switched to the main thread by Handler, processing the event in turn.
  4. Threadmode. BACKGROUND: In contrast to threadmode. MAIN, if an event is sent in a child thread, the event is processed directly in the child thread; If an event is sent on the main thread, it is first queued and then processed through the thread pool.
  5. Threadmode. ASYNC: In contrast to threadmode. MAIN_ORDERED, events are queued to whichever thread sends them and then executed through the thread pool


3. Register to register

Ok, so in order to use Eventbus, you need to register it first and see how to use it

EventBus.getDefault().register(this);
Copy the code

GetDefault () is a singleton that creates an EventBus instance object and returns it

public static EventBus getDefault(a) {
        
    if (defaultInstance == null) {
         synchronized (EventBus.class) {
             if (defaultInstance == null) {
                 defaultInstance = newEventBus(); }}}return defaultInstance;
}
Copy the code

Nothing more to say, keep looking at register

Look at the picture first

Look at the code

public void register(Object subscriber) { Class<? > subscriberClass = subscriber.getClass();// Get the bytecode file passed in for the class to register
     List<SubscriberMethod> subscriberMethods = 
     subscriberMethodFinder.findSubscriberMethods(subscriberClass); // ->> Analysis 1
     
     synchronized (this) {

         // The traversal subscription method encapsulates a collection of classes
         for (SubscriberMethod subscriberMethod : subscriberMethods) {
              subscribe(subscriber, subscriberMethod); // ->> Analysis 4}}}Copy the code

As you can see from the figure above, this method actually does two things

  1. Based on the bytecode file of the registered class, the findSubscriberMethods method is called to get the information set for all subscription methods on that registered class.
  2. Iterate over the information set and populate two maps with data: subscriptionsByEventType Gets all subscription method information sets based on events (event type, parameter type on subscription methods). TypesBySubscriber can get all the event types on the register class based on this register class.
/** * findSubscriberMethods() gets all Subscribe methods in the class to be registered, that is, the method with a Subscribe annotation, a public modifier, and a single parameter */
List<SubscriberMethod> findSubscriberMethods(Class
        subscriberClass) {

    // METHOD_CACHE: Is a ConcurrentHashMap, key is the bytecode file to register the class, value is the collection of all subscription method information in this bytecode file, and the element of the collection is SubscriberMethod, which is actually the information class of the subscription method. This includes Method objects, thread mode, event type, priority, stickiness, etc.
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); // This step is to check whether the method of the registered class has been cached, and then return the method according to the class
    if(subscriberMethods ! =null) {
        return subscriberMethods;
    }

    // EventBus supports EventBusBuilder. IgnoreGeneratedIndex is true if we define EventBusBuilder, false otherwise
    if (ignoreGeneratedIndex) {
        subscriberMethods = findUsingReflection(subscriberClass);
    } else {

        // ->> Analysis 2
        subscriberMethods = findUsingInfo(subscriberClass);
    }
    
    // If the class does not find a subscription method, an exception is thrown
    if (subscriberMethods.isEmpty()) {
        throw new EventBusException("Subscriber " + subscriberClass + " and its super classes have no public methods with the @Subscribe annotation");
    } else {
 
        // Store the class of type key and the class of value that encapsulates all registration methods of this class into the map collection
        METHOD_CACHE.put(subscriberClass, subscriberMethods);
        return subscriberMethods;

        // ->> return to the register () method}}Copy the code

METHOD_CACHE () : findUsingInfo () : findUsingInfo () : findUsingInfo () : findUsingInfo () : findUsingInfo () This is then stored in the cache (METHOD_CACHE) based on the key of the registered class and the value of the subscribed method.

/** * findUsingInfo() If findState cache, subscription method information, use the findState in the cache, otherwise call findUsingReflectionInSingleClass method, reflection method for subscription information. * /
private List<SubscriberMethod> findUsingInfo(Class
        subscriberClass) {
  
    // FindState helps us find the class for the subscription method, as described later
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);

    // findstate. clazz is our registered class
    while(findState.clazz ! =null) {

        findState.subscriberInfo = getSubscriberInfo(findState);

        // When this class is first registered, findState.subscriberInfo is null and we go false
        if(findState.subscriberInfo ! =null) {
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    if(findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); }}}else {

            // ->> Analysis 3
            findUsingReflectionInSingleClass(findState);
        }

        // Change findState.clazz to the parent Class of the subscriberClass. That is, you need to traverse the parent Class
        findState.moveToSuperclass();
    }

     // The found methods are saved in the subscriberMethods collection of the FindState instance. You then build a new List
      
        using subscriberMethods and return it, finally freeing the findState
      
    return getMethodsAndRelease(findState);

    // ->> return to the findSubscriberMethods() method
}
Copy the code
/ * * * analysis 3: findUsingReflectionInSingleClass role (*) : get information * / subscription method through reflection
private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
         // Get all methods in the subscription class by reflection
         methods = findState.clazz.getDeclaredMethods();
     } catch (Throwable th) {
         ...
     }

     // the traversal method
     for (Method method : methods) {

        // Get the method modifier
        int modifiers = method.getModifiers();

        // Methods are public, but not abstract, static, etc
        if((modifiers & Modifier.PUBLIC) ! =0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            
            // Get the modifier type of the methodClass<? >[] parameterTypes = method.getParameterTypes();// Only one parameter
            if (parameterTypes.length == 1) {

                // Get an annotation on the method named Subscribe
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                
                // If the method is annotated with Subscribe
                if(subscribeAnnotation ! =null) {
                       
                    // Gets the first parameter type on the subscription method, which is the event type of the subscriptionClass<? > eventType = parameterTypes[0];
                     
                    The checkAdd() method is used to determine whether a key-value pair has been added to FindState, and returns true if it has not
                    if (findState.checkAdd(method, eventType)) {
                            
                        // Get the thread mode
                        ThreadMode threadMode = subscribeAnnotation.threadMode();

                        // Encapsulate the SubscriberMethod, event type, thread mode, priority, whether sticky events are supported and other information into a SubscriberMethod object and add it to the subscriberMethods collection in findState
                        findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky()));

                         Return to the findUsingInfo() method}}}else if(strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { ... }}else if(strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { ... }}}Copy the code

Based on reflection, the information data for the subscription method is retrieved, packaged into a SubscriberMethod object, and added to the collection of findState.

/** * analysis 4: SUBSCRIBE () * function: basically build 2 map objects */
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    
    // Gets the event type of the subscription methodClass<? > eventType = subscriberMethod.eventType;// The subscription method encapsulates the class, and then encapsulates the registration class information
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    
    // subscriptionsByEventType is a hashMap with an event type of key and a Subscription set of value
    // First check subscriptionsByEventType to see if there is a value with the current event type as key
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);

    // If not
    if (subscriptions == null) {

        // Create a collection and merge the data according to the event type
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
        if (subscriptions.contains(newSubscription)) {
            throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "+ eventType); }}// Add the newSubscription object created above to the Subscriptions directory
    int size = subscriptions.size();
    for (int i = 0; i <= size; i++) {
  
        // Sort by priority
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break; }}// typesBySubscriber is also a HashMap that holds key-value pairs with the object currently being registered as the key and the set of parameter types of the methods that subscribe to events in the registered class as values
    // Select the set of parameter types for the subscribed methods in the subscribed classList<Class<? >> subscribedEvents = typesBySubscriber.get(subscriber);if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);

    // Whether sticky events are supported
    if (subscriberMethod.sticky) {
        
        // ->> Analysis 5. }Copy the code

With the two maps built, our registration is done

To summarize

Pass in the information of the registered class, get all the methods on the registered class according to the reflection, iterate over these methods, get the Subscribe methods (as long as one parameter has the permission of public and uses the Subscribe tag), encapsulate the information of the methods into the SubscriberMethod object and store it in the collection, then iterate over the collection. Take out the SubscriberMethod objects and merge them into Subscription objects according to the bytecode file of the registered class. Then, they are reclassified according to the event type and stored in map subscriptionsByEventType (key is event, Value is List), and then create map typesBySubscriber. The registration class is key and the List is value. Afterward.

4. Unregister cancels the registration

It’s easy to use

EventBus.getDefault().unregister(this);
Copy the code

Look at the picture

Look at the code

public synchronized void unregister(Object subscriber) {

    // ->> Analysis 6List<Class<? >> subscribedTypes = typesBySubscriber.get(subscriber);// If the set is not null
    if(subscribedTypes ! =null) {
            
         // Iterate through the collection to get the type of subscription event
         for(Class<? > eventType : subscribedTypes) {// ->> Analysis 7
              unsubscribeByEventType(subscriber, eventType);
         }
         typesBySubscriber.remove(subscriber);
     } else {
          logger.log(Level.WARNING, "Subscriber to unregister was not registered before: "+ subscriber.getClass()); }}Copy the code

Analysis 6: Remember the two maps we created when we analyzed the registration? One of them is typesBySubscriber, where key is the registration class and value is a set of event types (List). This step is to get the event types of all subscribed methods for that class based on the registration class.

/** * 7 */
private void unsubscribeByEventType(Object subscriber, Class
        eventType) {
        
    // According to the event type, get the collection of subscription method information corresponding to the event type
    List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    
    // If the set is not null
    if(subscriptions ! =null) {
            
        // Traverses the subscription method corresponding to the event type
        int size = subscriptions.size();
        for (int i = 0; i < size; i++) {
        
             // Get the Subscription object, which contains all information about the Subscription method and the registered class
             Subscription subscription = subscriptions.get(i);
             
             // subscriptionsByEventType contains more than 1 registered class, so we need to add the following interpretation, if the subscribed method is in the registered class we want to unregister
             if (subscription.subscriber == subscriber) {
                 subscription.active = false;

                 // Delete the subscription method from the collectionsubscriptions.remove(i); i--; size--; }}}}Copy the code

To summarize

In fact, unbinding is relatively simple. It mainly uses the two maps generated during registration, first finds all subscription events owned by the class according to typesBySubscriber, that is, according to the registered class to be unbound, and then traverses these subscription events, and then according to these subscription events, Find the set of subscription methods corresponding to this event in subscriptionsByEventType, traverse the set again to determine whether the registered class information of the subscription method is the registered class to be unbound. If so, remove the subscription method information to complete unbinding.

4. Post Events

It’s easy to use

EventBus.getDefault().post(new Object());
Copy the code

Look at the picture

Look at the code

public void post(Object event) {
       
    // ->> Analysis 8
    PostingThreadState postingState = currentPostingThreadState.get();
    
    // Get a queue stored in postingState
    List<Object> eventQueue = postingState.eventQueue;

    // The event to be sent is queued
    eventQueue.add(event);

    // Determine whether the event is being sent. If so, skip the following logic
    if(! postingState.isPosting) {// Check whether it is in the main thread
        postingState.isMainThread = isMainThread();
        postingState.isPosting = true;
        if (postingState.canceled) {
            throw new EventBusException("Internal error. Abort state was not reset");
        }
        try {

             // Walk through the queue
             while(! eventQueue.isEmpty()) {// ->> Analysis 9
                 postSingleEvent(eventQueue.remove(0), postingState); }}finally {
            
            // Reset the state
            postingState.isPosting = false;
            postingState.isMainThread = false; }}}Copy the code

Analysis of 8: PostingState actual wrapper class is a thread state, contains the event queue, thread state, identified, are sent to the Subscription information, such as currentPostingThreadState ThreadLocal, This means that postingState is unique to the thread and does not allow other threads to share data from the current thread

The post() method basically stores the sent event in a queue in postingState, which is thread specific, and passes the event through the loop to the postSingleEvent() method for processing.

/** * 9 */
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<? > eventClass = event.getClass();boolean subscriptionFound = false;

    // Whether to view all inheritance relationships
    if (eventInheritance) {
           
         Call lookupAllEventTypes () to get all the parent event types of the eventList<Class<? >> eventTypes = lookupAllEventTypes(eventClass);int countTypes = eventTypes.size();

         // Iterate over the event type
         for (int h = 0; h < countTypes; h++) { Class<? > clazz = eventTypes.get(h);// ->> Analysis 10subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); }}else {
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    }
     
    if(! subscriptionFound) {if (logNoSubscriberMessages) {
            logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
        }
            
        // If we do not subscribe to events, send NoSubscriberEvent
        if(sendNoSubscriberEvent && eventClass ! = NoSubscriberEvent.class && eventClass ! = SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); }}}Copy the code

PostSingleEvent () method, according to the eventInheritance properties, decide whether to traverse upward parent types of events, and then use postSingleEventForEventType further processing events () method.

/** * parse 10 */
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class
        eventClass) {

    CopyOnWriteArrayList<Subscription> subscriptions;
    synchronized (this) {

        // Remember the map subscriptionsByEventType built during registration? Get List
      
       , a collection of subscription methods, based on the event type
      
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    
    // If the set is not empty
    if(subscriptions ! =null && !subscriptions.isEmpty()) {
        
        // Go through the collection and retrieve the Subscription class
        for (Subscription subscription : subscriptions) {
                
            // Log events
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted = false;
            try {
 
                // Handle events ->> Analyze 11
                postToSubscription(subscription, event, postingState.isMainThread);
                aborted = postingState.canceled;
            } finally {
                postingState.event = null;
                postingState.subscription = null;
                postingState.canceled = false;
            }
            if (aborted) {
                break; }}return true;
    }
    return false;
}
Copy the code

This method is simple: find the collection of subscription method information in subscriptionsByEventType based on the event type, walk through the collection, get the wrapper class for the subscription method information, and call postToSubscription.

/** * 11 */
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {

    // Execute according to the thread mode set by the subscription method
    switch (subscription.subscriberMethod.threadMode) {
    
        // By default thread mode, events are received in the same thread as they are sent
        case POSTING:

            // ->> Analysis 12
            invokeSubscriber(subscription, event);
            break;

        // If it is the main thread, it is executed directly, the child thread is queued, and then it is switched to the main thread by Handler
        case MAIN:
            if (isMainThread) {

                // Main thread, direct reflection execution
                invokeSubscriber(subscription, event);
            } else {

                // ->> Analysis 13
                mainThreadPoster.enqueue(subscription, event);
            }
            break;

        // No matter which thread is in the queue, the queue is added and executed by handler on the main thread
        case MAIN_ORDERED:
            
            // ->> Analysis 13
            if(mainThreadPoster ! =null) {
                mainThreadPoster.enqueue(subscription, event);
            } else {
                invokeSubscriber(subscription, event);
            }
            break;

        // If in the child thread, execute directly, if in the main thread, queue, execute through the thread pool
        case BACKGROUND:
                
            if (isMainThread) {

                // ->> Analysis 15
                backgroundPoster.enqueue(subscription, event);
            } else {
 
                // In the child thread, direct reflection executes
                invokeSubscriber(subscription, event);
            }
            break;

        // No matter which thread executes, it is queued and executed with the thread pool
        case ASYNC:
             
             // AsyncPoster and backgroundPoster types, but AsyncPoster does not have a synchronization lock, which causes it to open a subthread each time it executes a task, while backgroundPoster does not
             asyncPoster.enqueue(subscription, event);
             break;
        default:
             throw new IllegalStateException("Unknown thread mode: "+ subscription.subscriberMethod.threadMode); }}/** * analysis 12: Execute */ directly through reflection calls
void invokeSubscriber(Subscription subscription, Object event) {

    try {
        subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
    } catch (InvocationTargetException e) {
        handleSubscriberException(subscription, event, e.getCause());
    } catch (IllegalAccessException e) {
        throw new IllegalStateException("Unexpected exception", e); }}MainThreadPoster */ mainThreadPoster */ mainThreadPoster */
 public class HandlerPoster extends Handler implements Poster {
 
    private final PendingPostQueue queue;
    private booleanhandlerActive; .public void enqueue(Subscription subscription, Object event) {
        // Encapsulate a PendingPost object with subscription and event
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            // Join the queue
            queue.enqueue(pendingPost);
            if(! handlerActive) { handlerActive =true;
                
                // sendMessage () sends a message to handle the event, and the handleMessage() method is executed to switch the child thread to the main thread
                if(! sendMessage(obtainMessage())) {throw new EventBusException("Could not send handler message"); }}}}@Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            // Walk through the queue
            while (true) {
                // Get the PendingPost object from the queuePendingPost pendingPost = queue.poll(); .// ->> Analysis 14eventBus.invokeSubscriber(pendingPost); . }}finally{ handlerActive = rescheduled; }}}/** * Analysis 14: Further processing the PendingPost object */
void invokeSubscriber(PendingPost pendingPost) {
     
    // Retrieve the event type
    Object event = pendingPost.event;

    // Retrieve the information wrapper class for the subscription method
    Subscription subscription = pendingPost.subscription;

    // Release the resource referenced by pendingPost
    PendingPost.releasePendingPost(pendingPost);
    if (subscription.active) {

        // Execute the subscription method through a reflection callinvokeSubscriber(subscription, event); }}/** * 15 */
final class BackgroundPoster implements Runnable.Poster {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

    private volatile boolean executorRunning;

    BackgroundPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {

        // Encapsulate a PendingPost object with subscription and event
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {

            // Join the queue
            queue.enqueue(pendingPost);
            if(! executorRunning) { executorRunning =true;

                // Call the newCachedThreadPool thread pool to execute the task
                eventBus.getExecutorService().execute(this); }}}@Override
    public void run(a) {
        try {
            try {

                // loop the queue
                while (true) {
                    
                    // Wait 1 second to retrieve the PendingPost object
                    PendingPost pendingPost = queue.poll(1000); .// ->> Analysis 14(above)eventBus.invokeSubscriber(pendingPost); }}catch (InterruptedException e) {
                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e); }}finally {
            executorRunning = false; }}}Copy the code

To summarize

Post is also easy. First of all, you save the sent event in the queue in postingState, which is unique to the thread, and then iterate through the queue in postingState, take out the set of all events under the thread, and then iterate through it, and then according to subscriptionsByEventType, Take out all subscription methods corresponding to the event, and then see whether it can be directly processed. If yes, the subscription method can be directly reflected to call; if not, the thread can be directly switched through HandlerPower, BackgroundPower and AsyncPower, and then the reflection call can be processed.

HandlerPower internally encapsulates a Handler. When each call is made, the first event is added to the queue, and then according to the Handler switch to the main thread, events are removed from the queue in order, and reflected execution

BackgroundPower is similar to an AsyncPower that encapsulates a catchThreadPool to perform a task, but does not have a synchronization lock in it. BackgroundPower will open a thread


Sticky events

What are sticky events? In general, we use EventBus to prepare the subscription event, then register the event, and finally send the event, that is, have the recipient of the event first. Sticky events, on the other hand, can be sent first, followed by methods for subscribing to events and registering events.

Let’s see how it works. It’s really easy, right

// Publish events
EventBus.getDefault().postSticky(new Object());

// Subscribe to events
@Subscribe(sticky = true)
public void testEventBus(Object obj){... }Copy the code

How does the re-register subscription method still receive previous events after the event is sent? Look at the picture

Figure below

Look at the code

public void postSticky(Object event) {

    // Very simple, the type of stickyEvents to be published and their corresponding events are stored in Map stickyEvents
    synchronized (stickyEvents) {
        stickyEvents.put(event.getClass(), event);
    }
    // This is a normal publishing event, as analyzed above
    post(event);
}
Copy the code

We put the types of sticky events we publish and the corresponding events into our map, so where do we do it? Remember analysis 5 we wrote above? Let me complete the code in the registration method

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {

    // Build those two important maps.// If the event supports sticky events
    if (subscriberMethod.sticky) {

        // If you need to look up the event's parent class
        if (eventInheritance) {
                
            // Walk through the set of sticky events we stored above and take out the sticky events stored insideSet<Map.Entry<Class<? >, Object>> entries = stickyEvents.entrySet();for(Map.Entry<Class<? >, Object> entry : entries) { Class<? > candidateEventType = entry.getKey();// If candidateEventType is a subclass of eventType
                if (eventType.isAssignableFrom(candidateEventType)) {
                    Object stickyEvent = entry.getValue();

                    // ->> Analyze 16checkPostStickyEventToSubscription(newSubscription, stickyEvent); }}}else{ Object stickyEvent = stickyEvents.get(eventType); checkPostStickyEventToSubscription(newSubscription, stickyEvent); }}}/** */
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        
    // If the method supports sticky events
    if(stickyEvent ! =null) {
            
        // This method is used to handle events according to the thread patternpostToSubscription(newSubscription, stickyEvent, isMainThread()); }}Copy the code

See, isn’t that easy? Let’s sum it up

To summarize

StickyEvents will store the stickyEvents event type and corresponding event in map stickyEvents at the time of sending stickyEvents. If a subscription method supports stickyEvents, stickyEvents will be removed at the time of registration. Then iterate through the processing event.

Okay, eventBus is done. Here’s a big picture to make a deeper impression


Look at the picture 6.

7. Last thing I want to say

In fact, this EventBus is one of the classic open source projects. It has a clever design, so you can write an EventBus manually. Plus, one more thought on this one

Does EventBus support cross-process? Why is that? You can leave a comment below


8. Next episode preview

Let’s manually lift a Butterknife ourselves