An article to get "EventBus Source Code Detailed Explanation (Full)"

foreword

The last few articles will have a clear analysis of common three-party libraries.
Including usage scenarios, basic usage, source code analysis, frequently asked questions, etc.
I hope that in the process of source code analysis, I can learn the concepts and ideas of the tripartite library design.
This article also invites EventBus to be a guest,
and will analyze it with the v3.3.1 version of EventBus.

Supplement: Be prepared, looking at the source code is very crashing (it’s almost crashing for me). But the importance of the source code does not need to be more than BB.

Brief description of EventBus

This article is based on analyzing the source code. Simply borrow the official to briefly describe what EventBus is.
Official explanation: EventBus can simplify the communication between components, make our code writing easier, effectively separate the event sender and receiver (that is, the meaning of decoupling), and avoid complex and error-prone dependencies and Lifecycle issues.
My understanding: it can replace the current component communication, such as the bloated Handler, so as to simplify the code and solve some life cycle bugs.

Use of EventBus

1. Introduce the EventBus library
First, add the following dependencies to the project's build.gradle file:

implementation 'org.greenrobot:eventbus:3.3.1'

Two, define the event class
EventBus is based on the event-driven mechanism, we need to define the event class to transfer data. The event class can be a POJO (Plain Old Java Object) class, representing a specific event. For example:

public class MessageEvent {
    
    
    public String message;

    public MessageEvent(String message) {
    
    
        this.message = message;
    }
}

3. Registering subscribers
In the life cycle of the Activity or Fragment that needs to receive events, we need to register and unregister subscribers. It can be registered in the onStart() method and unregistered in the onStop() method. Examples are as follows:

@Override
protected void onStart() {
    
    
    super.onStart();

    // 注册订阅者
    EventBus.getDefault().register(this);
}

@Override
protected void onStop() {
    
    
    super.onStop();

    // 取消注册订阅者
    EventBus.getDefault().unregister(this);
}

Fourth, define the event processing method
Subscribers process the received event by defining the event processing method. The event processing method needs to be annotated with @Subscribe, and can only have one parameter, which represents the received event object. Examples are as follows:

@Subscribe
public void onMessageEvent(MessageEvent event) {
    
    
    // 处理接收到的事件
    String message = event.message;
    // TODO: 处理接收到的数据
}

5. Publishing events
Where events need to be published, we can call the post() method of EventBus to publish events. Examples are as follows:

EventBus.getDefault().post(new MessageEvent("Hello, EventBus!"));

6. Receive events
When an event is published, EventBus will automatically call the subscriber's event processing method. Subscribers can receive the published events in the event processing method and process them accordingly.

7. Handling Event Thread Mode
The event processing method can specify different thread modes through the @Subscribe annotation, including ThreadMode.MAIN means executing in the main thread, ThreadMode.BACKGROUND means executing in the background thread, and ThreadMode.ASYNC means executing in a separate thread execute etc. Select the appropriate thread mode according to business needs.

EventBus source code analysis

Then explain our EventBus source code in the order we use it

Initialize and build an instance

We can see the two construction methods provided by EventBus.

  • EventBus.getDefault()
  • EventBus.builder()
    insert image description here

EventBus.getDefault()

We often use EventBus.getDefault() to obtain an instance to publish events. Let's look at the source code:
EventBus.java

public class EventBus {
    
    
    private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    private final Map<Object, List<Class<?>>> typesBySubscriber;
    private final Map<Class<?>, Object> stickyEvents;
    
    // 默认实例变量
    static volatile EventBus defaultInstance;
    
    // 默认的 EventBus 构建器
    private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
    
    // 双重校验锁式单例
    public static EventBus getDefault() {
    
    
        EventBus instance = defaultInstance;
        if (instance == null) {
    
    
            synchronized (EventBus.class) {
    
    
                instance = EventBus.defaultInstance;
                if (instance == null) {
    
    
                    instance = EventBus.defaultInstance = new EventBus();
                }
            }
        }
        return instance;
    }

    // 无参构造
    public EventBus() {
    
    
        this(DEFAULT_BUILDER);
    }
    
    // 可见的一个形参的构造
    EventBus(EventBusBuilder builder) {
    
    
        logger = builder.getLogger();
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadSupport = builder.getMainThreadSupport();
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        backgroundPoster = new BackgroundPoster(this);
        asyncPoster = new AsyncPoster(this);
        ........
    }   
}

Through the code, we can see that the overall getDefault() method is actually a double-check lock-type singleton writing method, in which the code for creating an instance calls a public no-argument construction, and this no-argument construction finally calls a parameter The constructor of EventBus(EventBusBuilder builder) passes in a default builder.

It can be seen that getDefault() actually calls the constructor of EventBus (EventBusBuilder builder) at the end. It is still the way of builder. It's just that getDefault() just helps us with the default configuration.

EventBus.builder()

This builder method provides an EventBus object that we can build ourselves. Through .build() we can configure the EventBus. So what can we all configure?
In the figure above, you can see the content of the chainable Builder. Let's take a look at the source code of EventBusBuilder to understand:
EventBusBuilder.java

@SuppressWarnings("unused")
public class EventBusBuilder {
    
    
    .....
    //构造函数
    EventBusBuilder() {
    
     }

    /** 配置订阅函数执行有异常时,是否打印异常信息   默认:true*/
    public EventBusBuilder logSubscriberExceptions(boolean logSubscriberExceptions) {
    
    
        this.logSubscriberExceptions = logSubscriberExceptions;
        return this;
    }

    /**
     * 配置订阅函数执行有异常时,是否发布 SubscriberExceptionEvent 事件
     * 默认:true
     */
    public EventBusBuilder sendSubscriberExceptionEvent(boolean sendSubscriberExceptionEvent) {
    
    ...}

    /**
     * 配置事件无匹配订阅函数时,是否发布 NoSubscriberEvent
     * 默认:true
     */
    public EventBusBuilder sendNoSubscriberEvent(boolean sendNoSubscriberEvent) {
    
    ...}

    /**
     * 如果订阅者方法执行有异常时,是否抛出 SubscriberException
     * 默认:false
     */
    public EventBusBuilder throwSubscriberException(boolean throwSubscriberException) {
    
    ...}

    /**
     * 配置是否事件继承
     */
    public EventBusBuilder eventInheritance(boolean eventInheritance) {
    
    ...}

    /**
     * 为 EventBus 提供一个自定义线程池,用于异步和后台事件传递。
     * 这是一个可以破坏事情的高级设置:确保给定的 ExecutorService 不会卡住以避免未定义的行为。
     */
    public EventBusBuilder executorService(ExecutorService executorService) {
    
    ...}

    /**
     * 跳过类的方法验证
     */
    public EventBusBuilder skipMethodVerificationFor(Class<?> clazz) {
    
    ...}

    /**
     * 配置是否即使有生成的索引也强制使用反射
     */
    public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) {
    
    ...}

    /**
     * 是否启用严格的方法验证
     */
    public EventBusBuilder strictMethodVerification(boolean strictMethodVerification) {
    
    ...}

    /**
     * 添加索引类
     */
    public EventBusBuilder addIndex(SubscriberInfoIndex index) {
    
    ...}

    /**
     * 为所有 EventBus 日志设置特定的日志处理程序
     * 默认情况下,所有日志记录都是通过 Android 上的 {@code android.util.Log} 或 JVM 上的 System.out。
     */
    public EventBusBuilder logger(Logger logger) {
    
    ...}

    /**
     * 获取 Logger
     */
    Logger getLogger() {
    
    ...}

    /**
     * 获取主线程支持
     */
    MainThreadSupport getMainThreadSupport() {
    
    ...}

    /**
     * 使用此构建器的值安装由 {@link EventBus#getDefault()} 返回的默认 EventBus
     * 在第一次使用默认 EventBus 之前必须只执行一次
     * 此方法调用后,再通过 {@link EventBus#getDefault()} 获取到的对象就是该构建器配置的实例
     * 所以该方法应该在最后调用
     */
    public EventBus installDefaultEventBus() {
    
    ...}

    /**
     * 根据当前配置构建 EventBus
     */
    public EventBus build() {
    
    
        return new EventBus(this);
    }
}

Important members of EventBus initialization

You can see that some members are initialized in EventBus (EventBusBuilder builder) (only important ones are kept)

private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;
    
EventBus(EventBusBuilder builder) {
    
    
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        backgroundPoster = new BackgroundPoster(this);
        asyncPoster = new AsyncPoster(this);
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
            builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        ........
}   

These initialized members are very important, in charge of our entire EventBus registration monitoring and sending process. Let's take a look at them one by one.

  • Map<Class<?>, CopyOnWriteArrayList> subscriptionsByEventType

All subscriber methods are stored, classified by the type of event received by the subscriber method. key: the Class object of the event class, value: the collection of wrapper classes for subscriber methods.

  • Map<Object, List<Class<?>>> typesBySubscriber

Used to store the event types received by the subscriber. key: Subscriber instance, value: List of Class objects of the received event types.

  • Map<Class<?>, Object> stickyEvents

Used to store the latest sticky event that currently exists. key: the Class object of the event class, value: the latest sticky event. is ConcurrentHashMap

  • Map<Class, List>> eventTypesCache = new HashMap<>()

Used to store all parent types of the event type, including superclasses and interfaces. key: the event Class object, value: all parent Class objects of the event Class object, including superclasses and interfaces

  • mainThreadPoster

Used to post and process events in the main thread. It is created by mainThreadSupport.createPoster(this), and the object will be created only when the main thread support (mainThreadSupport) is not null; otherwise, it is null.

  • backgroundPoster

Used to post and process events in a background thread. It is responsible for sending events to the background thread of the subscriber method for processing. This member variable is an instance of the BackgroundPoster class.

  • asyncPoster

Used to post and process events in an asynchronous thread. It is responsible for sending events to the asynchronous thread of the subscriber method for processing. This member variable is an instance of the AsyncPoster class.

  • subscriberMethodFinder

Subscription method finder: used to help us find the subscription method in the class registered with EventBus. And put it into the subscription collection.
Let's take a look at the role of these member variables in the process

registration process

In the code, we register through EventBus.getDefault().register(this) at onStart.

@Override
protected void onStart() {
    
    
    super.onStart();

    // 注册订阅者
    EventBus.getDefault().register(this);
}

So what happened after registration?

register method

You can look at the source code of register

public void register(Object subscriber) {
    
    

    //第一个If判断主要是判断是否是Android平台并且导入了Android的分支包,因为EventBus还支持Java平台
    //从 3.3.0 版本开始 greenrobot 将 EventBus 分离为 Java 和 Android 两部分,并且默认情况下引入的依赖为 Android 版本,Java 版本需要调整依赖地址。
    if (AndroidDependenciesDetector.isAndroidSDKAvailable() && !AndroidDependenciesDetector.areAndroidComponentsAvailable()) {
    
    
        // Crash if the user (developer) has not imported the Android compatibility library.
        throw new RuntimeException("It looks like you are using EventBus on Android, " +
                "make sure to add the \"eventbus\" Android library to your dependencies.");
    }

    // 1、反射获取订阅者的 Class 对象
    Class<?> subscriberClass = subscriber.getClass();
    // 2、通过 subscriberMethodFinder 订阅方法查找器去查找该Class的订阅者的订阅方法,
    //得到一个订阅方法List List<SubscriberMethod>
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    // 3、加同步锁,监视器为当前 EventBus 对象
    synchronized (this) {
    
    
        // 4、对订阅方法 List 进行遍历
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
    
    
             // 5、遍历到的每一个方法对其产生订阅关系,就是正式存放在订阅者的大集合中
            subscribe(subscriber, subscriberMethod);
        }
    }
}

0. First, detect the Android platform
1. Get the Class object of the subscriber by reflection: that is, the class we perform EventBus.getDefault().register(this)
2. Call findSubscriberMethods(Class< ?> subscriberClass) method to find the subscription method of the current subscriber instance
3. After getting all the subscription methods, call subscribe(Object subscriber, SubscriberMethod subscriberMethod) on the result and store the method in the total event collection.

Summary: This method first judges the platform, finds the subscription method, and puts it into the general collection for later publishing events. Next, we will further explain how to find the subscription method.

SubscriberMethodFinder class

This class is to find the subscription method. Still more important. The core methods for searching subscriptions later are all in this class, let us analyze this class first:

class SubscriberMethodFinder {
    
    
    private static final int BRIDGE = 0x40;
    private static final int SYNTHETIC = 0x1000;
    private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;
    /**
     * 订阅者方法缓存 ConcurrentHashMap,为了避免重复查找订阅者的订阅方法,维护了此缓存
     * key:   Class<?>                 订阅者 Class 对象
     * value: List<SubscriberMethod>>  订阅者方法 List
     */
    private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
    // 订阅者索引类集合
    private List<SubscriberInfoIndex> subscriberInfoIndexes;
    // 是否进行严格的方法验证 默认值为 false
    private final boolean strictMethodVerification;
    // 是否忽略生成的索引 默认值为 false
    private final boolean ignoreGeneratedIndex;
    // FIND_STATE_POOL 长度
    private static final int POOL_SIZE = 4;
    // FindState 池,默认4个位置 POOL_SIZE = 4
    private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];

    SubscriberMethodFinder(List<SubscriberInfoIndex> subscriberInfoIndexes, boolean strictMethodVerification, boolean ignoreGeneratedIndex) {
    
    ...}

    /**
     * 查找订阅者方法
     * @param subscriberClass Class<?> 订阅者 Class 对象
     * @return List<SubscriberMethod> 订阅者方法List
     */
    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    
    ...}

    /**
     * 查找订阅者方法
     * @param subscriberClass Class<?> 订阅者 Class 对象
     * @return List<SubscriberMethod> 订阅者方法 List
     */
    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    
    ...}

    /**
     * 从 FindState 中获取订阅者方法并正式发布
     * 该方法其实只是将形参 findState 中的 subscriberMethods 以新的 List 返回出来
     * 并且还对 findState 做了资源释放及回收的处理
     * @param findState FindState
     * @return List<SubscriberMethod> 订阅者方法
     */
    private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
    
    ...}

    /**
     * 准备 FindState,会从对象池中去获取,没有缓存的情况下会去 new 一个新对象
     * 此处运用了对象复用及池化技术
     * @return FindState
     */
    private FindState prepareFindState() {
    
    ...}

    /**
     * 获取索引类
     * @param findState FindState 查找状态类
     * @return SubscriberInfo 索引类
     */
    private SubscriberInfo getSubscriberInfo(FindState findState) {
    
    ...}

    /**
     * 通过反射查找订阅者方法
     * @param subscriberClass Class<?> 订阅者 Class 对象
     * @return List<SubscriberMethod> 订阅者方法 List
     */
    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
    
    ...}

    /**
     * 通过反射查找 {@link FindState#clazz} 对应类的订阅者方法
     * @param findState FindState
     */
    private void findUsingReflectionInSingleClass(FindState findState) {
    
    ...}

    /**
     * 查找状态
     * 主要就是在查找订阅者方法的过程中记录一些状态信息
     * FindState 类是 SubscriberMethodFinder 的内部类,这个方法主要做一个初始化的工作。
     * 由于该类中字段多,为了内存做了对象缓存池处理,见{@link #FIND_STATE_POOL}
     */
    static class FindState {
    
    
        // 订阅者方法 List
        final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
        // 按事件类型区分的方法 HashMap
        final Map<Class, Object> anyMethodByEventType = new HashMap<>();
        // 按方法签名存储
        final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
        // StringBuilder
        final StringBuilder methodKeyBuilder = new StringBuilder(128);
        // 订阅者的 Class 对象
        Class<?> subscriberClass;
        // 当前类的 Class 对象,该字段会随着从子类到父类查找的过程而进行赋值当前类的 Class 对象
        Class<?> clazz;
        // 是否跳过父类的方法查找
        boolean skipSuperClasses;
        // 索引类 初始值为 null
        SubscriberInfo subscriberInfo;

        /**
         * 为订阅者进行初始化
         * @param subscriberClass Class<?> 订阅者 Class 对象
         */
        void initForSubscriber(Class<?> subscriberClass) {
    
    ...}

        /**
         * 释放资源,准备下一次复用
         */
        void recycle() {
    
    ...}

        /**
         * 检查并将方法添加
         * @param method    Method 订阅方法
         * @param eventType Class<?> 事件 Class 对象,也就是该方法的形参
         * @return 校验结果
         */
        boolean checkAdd(Method method, Class<?> eventType) {
    
    ...}

        /**
         * 检查并将方法添加,对方法签名校验
         * @param method    Method 订阅方法
         * @param eventType Class<?> 事件 Class 对象,也就是该方法的形参
         * @return 校验结果
         */
        private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
    
    ...}

        /**
         * 移动到父类
         */
        void moveToSuperclass() {
    
    ...}
    }

Here we need to talk about the internal class FindState. He is a class that records our search process. Because our search process not only traverses the parent class, but also records all method information of the traversed class.

findSubscriberMethods method

First of all, subscriberMethodFinder is a subscription method finder, which is also initialized in EventBus (EventBusBuilder builder).
Let's analyze the findSubscriberMethods method in detail.
subscriberMethodFinder.findSubscriberMethods():

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    
    
    // 1、首先尝试从缓存中获取订阅方法 List
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    //2、判断从缓存中获取订阅方法 List 是否为null
    if (subscriberMethods != null) {
    
    
        return subscriberMethods;
    }

    // 3、是否忽略生成的索引(默认是False的)
    if (ignoreGeneratedIndex) {
    
    
        // 4、忽略索引的情况下,通过反射进行查找订阅者方法
        subscriberMethods = findUsingReflection(subscriberClass);
    } else {
    
    
        // 4、通过索引的方式进行查找 (更高效)
        subscriberMethods = findUsingInfo(subscriberClass);
    }
    
    // 5、如果没有订阅者方法,就抛出 EventBusException 异常
    if (subscriberMethods.isEmpty()) {
    
    
        throw new EventBusException("Subscriber " + subscriberClass
                + " and its super classes have no public methods with the @Subscribe annotation");
    } else {
    
    
         //6、 将此订阅者和其订阅者方法添加进缓存中 (下次不就有缓存了吗)
        METHOD_CACHE.put(subscriberClass, subscriberMethods);
        //7、返回结果List
        return subscriberMethods;
    }
}

1. First, try to obtain the subscriber's subscription method from the cache.
2. The subsequent code judges ignoreGeneratedIndex, which can be configured through EventBusBuilder.ignoreGeneratedIndex().
The default is false, that is, the default is index lookup (the advantages will be mentioned in the findUsingInfo index lookup below)

/** Forces the use of reflection even if there's a generated index (default: false). */
public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) {
    
    
    this.ignoreGeneratedIndex = ignoreGeneratedIndex;
    return this;
}

We can manually set him to True to go to the reflection search.

EventBus.builder().ignoreGeneratedIndex(true)

3. When ignoring the index class, use the reflection findUsingReflection(Class<?> subscriberClass) to search, if the index is not ignored, use the findUsingInfo(Class<?> subscriberClass) method to search.
4. After the search is completed, store the result in the METHOD_CACHE cache so that the next time you search for this subscriber, you can directly read the data from the cache.
5. Return the result

findUsingReflection method (reflection lookup)

Since it is the source code, don't be afraid to paste too much source code. Don't be afraid to read too much source code.

private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
    
    
    //1、获取一个 FindState 对象记录中间过程状态
    FindState findState = prepareFindState();
    //2、 为当前订阅者初始化 FindState
    findState.initForSubscriber(subscriberClass);
    //3、 循环 从子类到父类通过findUsingReflectionInSingleClass进行反射查找订阅方法
    while (findState.clazz != null) {
    
    
        //根据使用findState.clazz 再通过反射查找订阅方法
        findUsingReflectionInSingleClass(findState);
        // 查找阶段结束,移动到当前类的父类
        findState.moveToSuperclass();
    }
    //4、 返回查找到的订阅者方法并释放资源
    return getMethodsAndRelease(findState);
}

findUsingReflection mainly initializes the FindState state and drives findUsingReflectionInSingleClass to obtain the subscription method. Finally, iterate over the subclasses and parent classes.

findUsingReflectionInSingleClass method (reflection lookup)

I call him the big brother who really works, and obtains the subscription method through reflection.
The method source code is too long, if you don’t want to read it, don’t give up this article. I can briefly summarize this method:
1. Obtain the method of the current Class through reflection (here you need to pay attention to getMethods and getDeclaredMethods)

  • getMethods(): This method is to get all the public methods (modified by public modifier) ​​in this class and parent class or parent interface
  • getDeclaredMethods(): This method is to get all the methods in this class, including private (private, protected, default and public) methods. This is faster than getMethods(), especially when the subscriber is a huge class like Activity

2. Get the method information.

  • Modifier: Subscriber method has certain restrictions, must be public, not static volatile abstract strict
  • Parameter list: When the number of parameters is 1, it meets the limit of the number of parameters of the subscriber method
  • Annotation: Obtain the annotation of the method to determine whether there is a Subscribe
  • Threading model: wrapping SubscriberMethod for later distribution

Summary: Is it right? Don’t give up if you can’t read the source code. Brother will help you analyze and summarize. Isn't findUsingReflectionInSingleClass just pure work.

private void findUsingReflectionInSingleClass(FindState findState) {
    
    
    // 声明一个 方法数组
    Method[] methods;
    try {
    
    
        // 通过反射获取当前 Class 的方法,某些 Android 版本在调用 getDeclaredMethods 或 getMethods 时似乎存在反射错误
        // getMethods(): 该方法是获取本类以及父类或者父接口中所有的公共方法(public修饰符修饰的)。
        // getDeclaredMethods(): 该方法是获取本类中的所有方法,包括私有的(private、protected、默认以及public)的方法。
        // getDeclaredMethods() 这比 getMethods() 快,尤其是当订阅者是像活动这样的巨大的类时
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
    
    
        // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
        try {
    
    
            // 当 getDeclaredMethods() 发生异常时,尝试使用 getMethods()
            methods = findState.clazz.getMethods();
        } catch (LinkageError error) {
    
     // super class of NoClassDefFoundError to be a bit more broad...
            // 当 getMethods() 也产生了异常时,会抛出 EventBusException 异常
            String msg = "Could not inspect methods of " + findState.clazz.getName();
            if (ignoreGeneratedIndex) {
    
    
                msg += ". Please consider using EventBus annotation processor to avoid reflection.";
            } else {
    
    
                msg += ". Please make this class visible to EventBus annotation processor to avoid reflection.";
            }
            throw new EventBusException(msg, error);
        }
        // 跳过父类的方法查找,因为在此 catch 中已经获取了所有父类方法,所以要跳过父类
        findState.skipSuperClasses = true;
    }

    // 代码执行到此处表示反射获取方法没有产生异常
    // 对获取到的类中的所有方法进行遍历操作
    for (Method method : methods) {
    
    
        // 获取方法的修饰符
        int modifiers = method.getModifiers();
        // 订阅者方法有一定的限制,必须为 public,不能是static volatile abstract strict
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
    
    
        // 获取该方法的参数列表
        Class<?>[] parameterTypes = method.getParameterTypes();

        // 对参数个数进行判断
        if (parameterTypes.length == 1) {
    
    
            // 参数个数为1的情况下,符合订阅者方法对于参数个数的限制
            // 获取方法的注解,判断是否存在 Subscribe
            Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
            if (subscribeAnnotation != null) {
    
    
                // 如果方法存在 Subscribe 注解
                // 获取方法参数的 Class 对象
                Class<?> eventType = parameterTypes[0];
                // 对订阅者方法进行二级校验
                if (findState.checkAdd(method, eventType)) {
    
    
                    // 获取订阅者方法的线程模型
                    ThreadMode threadMode = subscribeAnnotation.threadMode();
                    // 将此订阅者方法 添加进 subscriberMethods
                    findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                        subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                }
            }
        } else
        // 继续严格的方法验证判断
            if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
    
    
                    String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                    throw new EventBusException("@Subscribe method " + methodName +
                            "must have exactly 1 parameter but has " + parameterTypes.length);
                }

    } else
        // 方法不是 public,进一步判断
        // 判断是否进行严格的方法验证,如果是,再判断当前方法是否有 Subscribe 注解
        // 两个条件都成立的情况下,抛出 EventBusException 异常,该异常来自于严格的方法验证
        if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
    
    
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException(methodName +
                        " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
            }
    }
}

findUsingInfo method (index lookup)

findUsingInfo is an optimization technique used in EventBus.
First of all, how is this index generated?

  • During the initialization process, EventBus will traverse all subscriber classes, analyze their subscription methods and generate an index data structure to provide fast event lookup. This process will parse the subscription method of the subscriber class, extract the parameter information and event type of the subscription method, and store them in a Map data structure.

What are the advantages?

  • The index is established according to the event type, and the method corresponding to the subscriber can be quickly found to improve the efficiency of event scheduling. Index lookup does not require reflection, so it is relatively more efficient.

As mentioned above, if you can’t read the source code, I will summarize it for you. look down! ! ! ! !

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    
    
    // 获取一个 FindState 对象
    FindState findState = prepareFindState();
    // 为当前订阅者初始化 FindState
    findState.initForSubscriber(subscriberClass);
    // 循环 从子类到父类查找订阅方法
    while (findState.clazz != null) {
    
    
        // 获取索引类并赋值给 findState.subscriberInfo
        findState.subscriberInfo = getSubscriberInfo(findState);
        // 当索引类的信息类不为 null 时,进一步操作
        if (findState.subscriberInfo != null) {
    
    
            // 获取索引类的所有订阅者方法
            SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
            // 对订阅者方法数组遍历
            for (SubscriberMethod subscriberMethod : array) {
    
    
                // 检查并将方法添加
                if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
    
    
                    // 校验通过,将该订阅方法添加至 subscriberMethods,
                    findState.subscriberMethods.add(subscriberMethod);
                }
            }
        } else {
    
    
            // 如果没有索引类,就使用反射的方式继续查找
            findUsingReflectionInSingleClass(findState);
        }
        // 将 findState 的 Class 对象移至父类型
        findState.moveToSuperclass();
    }
    // 返回查找到的订阅者方法并释放资源
    return getMethodsAndRelease(findState);
}

The first part of this method is consistent with findUsingReflection(Class<?> subscriberClass), the difference is the logic in the loop body.
Then just talk about what is in the loop body:
1. First, get the index class through getSubscriberInfo
2. When the information class of the index class is not null, get the subscription method of the index class
3. Then traverse the verification (and reflection verification The same will not be repeated)
4. When the index class is not obtained, continue to use the findUsingReflectionInSingleClass(FindState findState) method to search reflectively

checkAdd method (secondary detection)

You can see the checkAdd method in both reflection search and index search final checks.

findState.checkAdd(method, eventType)

What did you check?
I don’t want to look at the source code below: Let me tell you what you have checked

  1. Classes in Java have an inheritance relationship. If the parent class declares the Subscribe method, it means that the subclass also holds the listening method. Then the subclass needs to get all the Subscribe methods of the parent class after registering.
  2. If the subclass inherits and rewrites the Subscribe method of the parent class, then the subclass needs to refer to the rewritten method after registering, ignoring the corresponding method of the parent class

This method is to judge this matter. Add the exact listener method to the collection. And like the above ignored methods filter out.

    boolean checkAdd(Method method, Class<?> eventType) {
    
    
            // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
            // Usually a subscriber doesn't have methods listening to the same event type.

            Object existing = anyMethodByEventType.put(eventType, method);
            if (existing == null) {
    
    
                //existing 等于 null 说明之前未解析到监听相同事件的方法,检查通过
                //因为大部分情况下监听者不会声明多个监听相同事件的方法,所以先进行这步检查效率上会比较高
                return true;
            } else {
    
     //existing 不等于 null 说明之前已经解析到同样监听这个事件的方法了

                if (existing instanceof Method) {
    
    
                    if (!checkAddWithMethodSignature((Method) existing, eventType)) {
    
    
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    // Put any non-Method object to "consume" the existing Method
                    //会执行到这里,说明存在多个方法监听同个 Event,那么将将 eventType 对应的 value 置为 this
                    //避免多次检查,让其直接去执行 checkAddWithMethodSignature 方法
                    anyMethodByEventType.put(eventType, this);
                }
                return checkAddWithMethodSignature(method, eventType);
            }
        }

        private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
    
    
            methodKeyBuilder.setLength(0);
            methodKeyBuilder.append(method.getName());
            methodKeyBuilder.append('>').append(eventType.getName());

            //以 methodName>eventTypeName 字符串作为 key
            //通过这个 key 来判断是否存在子类重写了父类方法的情况
            String methodKey = methodKeyBuilder.toString();
            //获取声明了 method 的类对应的 class 对象
            Class<?> methodClass = method.getDeclaringClass();

            Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
            //1. 如果 methodClassOld == null 为 true,说明 method 是第一次解析到,允许添加
            //2. 如果 methodClassOld.isAssignableFrom(methodClass) 为 true
            //2.1、说明 methodClassOld 是 methodClass 的父类,需要以子类重写的方法 method 为准,允许添加
            //     实际上应该不存在这种情况,因为 EventBus 是从子类开始向父类进行遍历的
            //2.2、说明 methodClassOld 是 methodClass 是同个类,即 methodClass 声明了多个方法对同个事件进行监听 ,也允许添加
            if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
    
    
                // Only add if not already found in a sub class
                return true;
            } else {
    
    
                // Revert the put, old class is further down the class hierarchy
                //由于 EventBus 是从子类向父类进行解析
                //会执行到这里就说明之前已经解析到了相同 key 的方法,对应子类重写了父类方法的情况
                //此时需要以子类重写的方法 method 为准,所以又将 methodClassOld 重新设回去
                subscriberClassByMethodKey.put(methodKey, methodClassOld);
                return false;
            }
        }

How to subscribe

In the register method,
after finding the subscription method of the current class through subscriberMethodFinder,
finally traverse the method collection and call subscribe(Object subscriber, SubscriberMethod subscriberMethod)
to fill the subscription method into the large collection of subscribers and classify the subscribers

    // 2、通过 subscriberMethodFinder 订阅方法查找器去查找该Class的订阅者的订阅方法,
    //得到一个订阅方法List List<SubscriberMethod>
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    // 3、加同步锁,监视器为当前 EventBus 对象
    synchronized (this) {
    
    
        // 4、对订阅方法 List 进行遍历
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
    
    
             // 5、遍历到的每一个方法对其产生订阅关系,就是正式存放在订阅者的大集合中
            subscribe(subscriber, subscriberMethod);
        }
    }

Then take a look at what subscribe has done?
In fact, we said before that the HashMap member variable subscriptionsByEventType initialized by EventBus. Used to store our subscribers.

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
subscriptionsByEventType = new HashMap<>();
  • In fact, subscribe is to package the acquired subscriber information into a Subscription object and add the corresponding Class as a Key to this collection.
  • And these subscriber information are added to the typesBySubscriber collection according to the classification.
private final Map<Object, List<Class<?>>> typesBySubscriber;
typesBySubscriber = new HashMap<>();

EventBus.subscribe()

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    
    
    // 获取订阅者方法接收的事件类型 Class 对象
    Class<?> eventType = subscriberMethod.eventType;
    // 创建 Subscription
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    // 从 subscriptionsByEventType 中 尝试获取当前订阅方法接收的事件类型的值
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions == null) {
    
    
        // 如果为 null,表示该方法是第一个,创建空的CopyOnWriteArrayList put 进 subscriptionsByEventType
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
    
    
        // 如果不为 null,判断现有数据中是否存在该方法,如果存在抛出 EventBusException 异常
        if (subscriptions.contains(newSubscription)) {
    
    
            throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                    + eventType);
        }
    }

    // 遍历当前事件类型的所有接收方法 将订阅者根据消息优先级高低进行排序
    int size = subscriptions.size();
    for (int i = 0; i <= size; i++) {
    
    
        // 这一步主要是将订阅者方法添加进 subscriptionsByEventType 数据中,并且会按照优先级进行插入
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
    
    
            subscriptions.add(i, newSubscription);
            break;
        }
    }
    // 获取当前订阅者接收的事件类型的数据
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
    
    
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    // 将当前的事件类型添加进订阅者的接收范围内
    subscribedEvents.add(eventType);

    // 对黏性事件进行处理(后面将)
    ...
}

Summarize what this subscribe method does:
1. First obtain the value of the event type received by the current subscription method from subscriptionsByEventType, a collection distinguished by event type.
2. If it is empty, it means that the method is the first one, and then create a CopyOnWriteArrayList Store the wrapper class of the subscription method in the collection and then store it in subscriptionsByEventType; (ps: this means that the subscribers are all placed in the subscriptionsByEventType large collection) 3.
Insert the original data in order according to the priority of the subscription method In the collection
4. Use subscriberMethod.eventType to classify subscribers and put them into the typesBySubscriber collection
5. Now that you want to classify, what is subscriberMethod.eventType?

subscriberMethod.eventType

In the findUsingReflectionInSingleClass method, the parameter type array parameterTypes of the subscriber method is obtained through method.getParameterTypes(), where parameterTypes[0] is the first parameter type of the subscriber method, which is the event type. This event type can be any Class object, indicating that the subscriber method can receive events of this type.
The source code is as follows:

private void findUsingReflectionInSingleClass(FindState findState) {
    
    
    ......
    Class<?>[] parameterTypes = method.getParameterTypes();
    if (parameterTypes.length == 1) {
    
      //方法包含的参数个数是一
       Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
       if (subscribeAnnotation != null) {
    
     //方法签名包含 Subscribe 注解
            Class<?> eventType = parameterTypes[0];
    ........

For example, if a subscriber method is defined as

@Subscribe
public void onEvent(MessageEvent event) {
    
    
    //处理事件
}

Then subscriberMethod.eventType is MessageEvent.class.
Through subscriberMethod.eventType, the subscriber method can be registered with EventBus, and matched and called when the event is sent.

summary

OK, that's all for the registration process. The content looks like a lot. It's okay to go down carefully. After all, EventBus, as the boss of the observer mode, mainly registers and publishes. So this is already half the content, hee hee.
The overall flow chart is as follows:
insert image description here

normal send

EventBus.getDefault().post(Any)

First of all, what is done in the post method of ordinary sending?

post method

This source code still needs to be looked at, even if I can give you a summary, I still recommend it (relatively simple). The summary is placed after the source code.

//PostingThreadState 主要作用是记录当前线程的事件发布状态、待发布事件等。
//是 EventBus 类的静态内部类
final static class PostingThreadState {
    
    
    // 事件队列
    final List<Object> eventQueue = new ArrayList<>();
    // 是否在发布
    boolean isPosting;
    // 是否是主线程
    boolean isMainThread;
    // 订阅者方法包装类
    Subscription subscription;
    // 正在发送的事件
    Object event;
    // 是否已经取消
    boolean canceled;
}

//ThreadLocal 为每个发送消息的线程维护一个 PostingThreadState 对象,
//用于为每个线程维护一个消息队列及其它辅助参数
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
    
    
        @Override
        protected PostingThreadState initialValue() {
    
    
            return new PostingThreadState();
        }
};

public void post(Object event) {
    
    
    // 从当前线程中取得线程专属变量 PostingThreadState 实例
    PostingThreadState postingState = currentPostingThreadState.get();
    // 拿到事件队列
    List<Object> eventQueue = postingState.eventQueue;
    // 将事件入队
    eventQueue.add(event);
    // 判断当前线程是否在发布事件中
    if (!postingState.isPosting) {
    
    
        // 设置当前线程是否是主线程
        postingState.isMainThread = isMainThread();
        // 将当前线程标记为正在发布
        postingState.isPosting = true;
        // 如果 canceled 为 true,则是内部错误,中止状态未重置
        if (postingState.canceled) {
    
    
            throw new EventBusException("Internal error. Abort state was not reset");
        }
        try {
    
    
            // 队列不为空时,循环发布单个事件
            while (!eventQueue.isEmpty()) {
    
    
                // 从事件队列中取出一个事件进行发布
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
    
    
            // 发布完成后 重置状态
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}

In general, the incoming messages of each post will be stored in the message queue eventQueue first, and then processed through the while loop. The message processing logic is completed through the postSingleEvent method. So the focus is on the postSingleEvent method.

postSingleEvent method

Let me talk about what he does first: (did two big things)

  • The first thing is to deal with the inheritance relationship of the event and find out all the parent types of the event class
  • The second thing is to further perform the operation of publishing events according to the event type

Look at the source code: (The summary is put later, in fact, the source code is already very clear)

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    
    
    // 获取事件的Class对象
    Class<?> eventClass = event.getClass();
    // 订阅者是否找到
    boolean subscriptionFound = false;
    // 判断是否处理事件继承
    if (eventInheritance) {
    
    
        // 查找所有事件类型
        List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
        // 循环遍历 所有类型
        int countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
    
    
            Class<?> clazz = eventTypes.get(h);
            // 按类型发布事件
            subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
        }
    } else {
    
    
        // 按类型发布事件
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    }
    // 如果没有找到对应的订阅关系
    if (!subscriptionFound) {
    
    
        // 判断事件无匹配订阅函数时,是否打印信息
        if (logNoSubscriberMessages) {
    
    
            logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
        }
        // 判断事件无匹配订阅函数时,是否发布 NoSubscriberEvent
        if (sendNoSubscriberEvent
            && eventClass != NoSubscriberEvent.class
            && eventClass != SubscriberExceptionEvent.class) {
    
    
            // 发布 NoSubscriberEvent
            post(new NoSubscriberEvent(this, event));
        }
    }
}
  1. Has an inheritance relationship. At this point, you need to get all the parent types of EventA, and then send messages sequentially according to all the monitoring methods associated with EventA itself and its parent types
  2. There is no inheritance relationship. At this point, you only need to send a message to the listening method of EventA

Sending a message is in the postSingleEventForEventType method

postSingleEventForEventType method

This method will return a Boolean result indicating whether the event was published successfully.

  • The method body obtains the subscription method of this event type from subscriptionsByEventType, returns false if there is no subscription method, and further processes if there is a subscription method.
    • Everyone remembers subscriptionsByEventType. Let me emphasize: store all subscriber methods, and classify them according to the type of event received by the subscriber method.
  • The next step is to traverse all the subscriber methods of the event type obtained, and assign the event to be sent and the subscriber method of the event to the PostingThreadState object of the current thread for recording.
  • Call the postToSubscription(Subscription subscription, Object event, boolean isMainThread) method to further process the thread mode for publishing

Look at the source code again:

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
    
    
    CopyOnWriteArrayList<Subscription> subscriptions;
    // 加锁 监视器为当前对象
    synchronized (this) {
    
    
        // 获取该 Class 对象的订阅方法 List
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    if (subscriptions != null && !subscriptions.isEmpty()) {
    
    
        // 如果存在订阅方法,就进行遍历操作
        for (Subscription subscription : subscriptions) {
    
    
            // 将事件和订阅方法赋值给 postingState
            postingState.event = event;
            postingState.subscription = subscription;
            // 是否中止
            boolean aborted;
            try {
    
    
                // 将事件发布到订阅者
                postToSubscription(subscription, event, postingState.isMainThread);
                // 是否已经取消发布
                aborted = postingState.canceled;
            } finally {
    
    
                // 重置 postingState 状态
                postingState.event = null;
                postingState.subscription = null;
                postingState.canceled = false;
            }
            // 如果已经中止,就跳出循环
            if (aborted) {
    
    
                break;
            }
        }
        // 方法体结束,返回找到订阅关系
        return true;
    }
    // 到此步骤表示没有订阅方法,返回 false
    return false;
}

postToSubscription method

In the above steps, postToSubscription will eventually be called to publish events to subscribers.
Here we need to talk about its Mode type.
Currently, EventBus has five thread modes, which are:

model effect
ThreadMode.POSTING By default, event delivery is done synchronously, and all subscribers will be called once the publication is complete. There is no thread switching. Therefore, this is the recommended pattern for simple tasks that are known to complete in a very short time without the need for the main thread. Event handlers using this pattern should return quickly to avoid blocking the posting thread, which may be the main thread.
ThreadMode.MAIN On Android, the Subscriber will be invoked on Android's main thread (the UI thread). If the publishing thread is the main thread, the subscriber method will be called directly, blocking the publishing thread. Otherwise, the event is queued for delivery (non-blocking). Subscribers using this pattern must return quickly to avoid blocking the main thread.
ThreadMode.MAIN_ORDERED On Android, the Subscriber will be invoked on Android's main thread (the UI thread). Unlike MAIN, this event will always be queued for delivery. This ensures that post calls are non-blocking. This gives a stricter, more consistent order for event handling
ThreadMode.BACKGROUND On Android, the subscriber will be called on a background thread. If the publishing thread is not the main thread, the subscriber method will be called directly in the publishing thread. If the publishing thread is the main thread, EventBus uses a single background thread, which will deliver all of its events sequentially. Subscribers using this pattern should return as quickly as possible to avoid blocking background threads.
ThreadMode.ASYNC This is always independent of the posting thread and the main thread. Published events never wait for event handler methods using this pattern. This pattern should be used if the execution of the event handler method may take some time, such as network access. Avoid triggering a large number of long-running asynchronous handler methods at the same time to limit the number of concurrent threads.

Then take a look at the postToSubscription source code:

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    
    
    // 按照订阅者方法指定的线程模式进行针对性处理
    switch (subscription.subscriberMethod.threadMode) {
    
    
        // 发布线程
        case POSTING:
        invokeSubscriber(subscription, event);
        break;
        // Android 上为主线程,非 Android 与 POSTING 一致
        case MAIN:
        // 判断是否是主线程,如果是主线程,直接调用 void invokeSubscriber(Subscription subscription, Object event) 方法进行在当前线程中发布事件
        if (isMainThread) {
    
    
            invokeSubscriber(subscription, event);
        } else {
    
    
            // 不是主线程,将该事件入队到主线程事件发布器处理
            mainThreadPoster.enqueue(subscription, event);
        }
        break;
        // Android 上为主线程,并且按顺序发布,非 Android 与 POSTING 一致
        case MAIN_ORDERED:
        if (mainThreadPoster != null) {
    
    
            // 不考虑当前的线程环境,直接入队,保证顺序
            mainThreadPoster.enqueue(subscription, event);
        } else {
    
    
            // 不是主线程,将该事件入队到主线程事件发布器处理
            // temporary: technically not correct as poster not decoupled from subscriber
            invokeSubscriber(subscription, event);
        }
        break;
        // Android 上为后台线程调用,非 Android 与 POSTING 一致
        case BACKGROUND:
        // 主线程发布的事件才会被入队到 backgroundPoster,非主线程发布的事件会被直接调用订阅者方法发布事件
        if (isMainThread) {
    
    
            backgroundPoster.enqueue(subscription, event);
        } else {
    
    
            invokeSubscriber(subscription, event);
        }
        break;
        // 使用单独的线程处理,基于线程池
        case ASYNC:
        // 入队 asyncPoster,该线程模式总是在非发布线程处理订阅者方法的调用
        asyncPoster.enqueue(subscription, event);
        break;
        default:
        throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
    }
}

can be seen. Different operations are performed by the type of Mode in the source code. But the process is the same. Then let's take a look at the important operations and members.
First of all, you can see that invokeSubscriber(subscription, event) will be called;
this method is the last calling method, let us talk about this method first.

invokeSubscriber method

It’s better to directly upload the source code (because it’s very simple and short):
In fact, we get our subscription object and call this method through reflection. So as to achieve the function of callback.

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);
    }
}

It's not over here yet. Because there is an if judgment above, it is not necessary to directly call invokeSubscriber.

publisher

mainThreadPoster, backgroundPoster, and asyncPoster
must be remembered by good friends in memory. Yes, it is when the EventBusBuilder is initialized.

mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);

So what did the three of them do, let us take a look at them one by one.
First of all, they all implement the Poster interface. The source code of the interface is as follows:

public interface Poster {
    
    

    /**
     * 将要为特定订阅发布的事件排入队列
     * @param subscription Subscription 接收事件的订阅方法包装类
     * @param event        Object 将发布给订阅者的事件
     */
    void enqueue(Subscription subscription, Object event);
}

mainThreadPoster

He is Poster. Just say that if it is not the main thread, just join the queue.

private final Poster mainThreadPoster;

AsyncPoster

For AsyncPoster, every time it receives a message, it will directly submit itself (Runnable) to the thread pool for processing in the enqueue method, and the thread pool used is Executors.newCachedThreadPool() by default. Tasks will be processed by threads immediately, so AsyncPoster does not guarantee the order of message processing, but the timeliness of message processing will be relatively high, and each message submitted to AsyncPoster may be processed by a different thread
The source code is as follows:

class AsyncPoster implements Runnable, Poster {
    
    

    // 待发布事件队列
    private final PendingPostQueue queue;
    private final EventBus eventBus;

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

    /**
     * 入队
     * @param subscription Subscription 接收事件的订阅者方法包装类
     * @param event        Object 将发布给订阅者的事件
     */
    public void enqueue(Subscription subscription, Object event) {
    
    
        // 获取一个 PendingPost
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        // 入队
        queue.enqueue(pendingPost);
        // 将任务提交到线程池处理,每个事件都会单独提交,不同于 BackgroundPoster
        eventBus.getExecutorService().execute(this);
    }

    @Override
    public void run() {
    
    
        // 获取队头的元素 一一对应,一次任务执行消费一个事件元素
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
    
    
            throw new IllegalStateException("No pending post available");
        }
        // 调用订阅者方法发布事件
        eventBus.invokeSubscriber(pendingPost);
    }
}

backgroundPoster

BackgroundPoster will cache tasks in PendingPostQueue in turn, and only take out one task each time and hand it over to the thread pool for execution, so BackgroundPoster will ensure the orderliness of message queue processing, but the timeliness of message processing is lower than that of AsyncPoster Some

final class BackgroundPoster implements Runnable, Poster {
    
    
    // 待发布事件队列
    private final PendingPostQueue queue;
    private final EventBus eventBus;
    // 执行器运行状态 volatile 可见性保障
    private volatile boolean executorRunning;

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

    public void enqueue(Subscription subscription, Object event) {
    
    
        // 获得一个 PendingPost
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        // 加锁 监视器为当前对象
        synchronized (this) {
    
    
            // 入队
            queue.enqueue(pendingPost);
            // 判断执行器是否在执行
            if (!executorRunning) {
    
    
                // 设置状态为正在执行
                executorRunning = true;
                // 向线程池提交任务
                eventBus.getExecutorService().execute(this);
            }
        }
    }

    @Override
    public void run() {
    
    
        try {
    
    
            try {
    
    
                // 循环处理队列中的所有待发布事件
                while (true) {
    
    
                    // 取出队头的元素
                    PendingPost pendingPost = queue.poll(1000);
                    // 二次校验
                    if (pendingPost == null) {
    
    
                        // 第二级校验是同步的
                        synchronized (this) {
    
    
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
    
    
                                // 最终没有元素,将执行器置为空闲
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    // 调用订阅者方法
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
    
    
                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interrupted", e);
            }
        } finally {
    
    
            // 执行完后将运行状态置为空闲
            executorRunning = false;
        }
    }
}

No matter what message processing strategy is used, the listener method is ultimately invoked by calling the invokeSubscriber method

sticky event

Sticky event handling on registration

In subscribe, we can see that the sticky method is processed, and finally the event is detected and published through checkPostStickyEventToSubscription.
Let’s not go into details, this time I know why the event is stuck in the register.
It is because we will call subscribe in register to put our listener events into the collection, and handle sticky events at the same time. It's been dealt with~ it's been dealt with~ it's been dealt with.

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    
    
    ........
    ........
    // 对黏性事件进行处理
    if (subscriberMethod.sticky) {
    
    
        // 是否事件继承
        if (eventInheritance) {
    
    
            // 必须考虑所有 eventType 子类的现有粘性事件。
            // Note: 迭代所有事件可能会因大量粘性事件而效率低下,因此应更改数据结构以允许更有效的查找
            // (e.g. 存储超类的子类的附加映射: Class -> List<Class>).
            Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
            for (Map.Entry<Class<?>, Object> entry : entries) {
    
    
                Class<?> candidateEventType = entry.getKey();
                // 判断 eventType 是否是 candidateEventType 的父类或父接口
                if (eventType.isAssignableFrom(candidateEventType)) {
    
    
                    Object stickyEvent = entry.getValue();
                    // 如果是父子关系  进行事件检查和发布
                    checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                }
            }
        } else {
    
    
            // 从黏性事件 Map 中获取当前事件类型的最新事件
            Object stickyEvent = stickyEvents.get(eventType);
            // 校验事件并发布事件
            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
        }
    }
}

First of all, like ordinary events, it is judged whether the event handles the inheritance relationship. If not, the latest event of this event type is directly obtained from stickyEvents to verify and publish. Because there may not be any sticky events that have been released, so pass The checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) method checks and publishes the event.

checkPostStickyEventToSubscription method

Directly upload the source code: If the source code is small, I will directly upload it. After all, you can’t read a few lines.

/**
 * 检查黏性事件并发布到订阅者
 *
 * @param newSubscription Subscription 订阅者方法包装类
 * @param stickyEvent     Object 黏性事件
 */
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
    
    
    if (stickyEvent != null) {
    
    
        // 如果订阅者试图中止事件,它将失败(在发布状态下不跟踪事件)
        // --> Strange corner case, which we don't take care of here.
        // 将事件发布到订阅者
        postToSubscription(newSubscription, stickyEvent, isMainThread());
    }
}
  • If the event is not empty, call the postToSubscription(Subscription subscription, Object event, boolean isMainThread) method to process the thread mode for further publishing
  • postToSubscription. We just talked about it. Isn't that just judging the type according to ThreadMode and finally reflecting it to the monitoring method through invokeSubscriber?

Summary: Do you feel like hitting yourself? When you register, you find that you are a sticky subscriber. Tell postToSubscription to publish a sticky event that matches you.
So where did this sticky event come from?

Proactively publish sticky events

I can really spark a conversation.
Active posting of sticky events is done by calling the postSticky(Object event) method.

EventBus.getDefault().postSticky(Any)

The source code of the method is as follows:

/**
 * 将给定事件发布到事件总线并保留该事件(因为它是黏性的).
 * 事件类型的最新粘性事件保存在内存中,供订阅者使用 {@link Subscribe#sticky()} 将来访问。
 */
public void postSticky(Object event) {
    
    
    // 加锁 监视器为黏性事件 Map
    synchronized (stickyEvents) {
    
    
        // 将事件存入内存中 以事件的 Class 对象为 key,事件实例为 value
        stickyEvents.put(event.getClass(), event);
    }
    // 放置后应发布,以防订阅者想立即删除
    post(event);
}

First store the sticky event in stickyEvents, and then call the post(Object event) method to publish the event. The source code of the method is as follows:
Why is it stored? of course! ! You look at the source code of subscribe, take it out and use it, take it out and send it to yourself. Use it yourself.

remove sticky event

Removing the specified sticky event can be achieved through the following methods, both of which are used to remove the specified event from stickyEvents.

public boolean removeStickyEvent(Object event) {
    
    
        synchronized (stickyEvents) {
    
    
            Class<?> eventType = event.getClass();
            Object existingEvent = stickyEvents.get(eventType);
            if (event.equals(existingEvent)) {
    
    
                stickyEvents.remove(eventType);
                return true;
            } else {
    
    
                return false;
            }
        }
    }

Cancellation process

Finally arrived at the final logout process.

  • Why do you want to log out?

The purpose of deregistration is to avoid memory leaks. EventBus uses a singleton mode. If you do not actively deregister, EventBus will always hold the subscriber. Deregistration is achieved through the unregister method

  • How to log out?

The source code is rarely uploaded directly to the source code

public synchronized void unregister(Object subscriber) {
    
    
    // 获取订阅者接收的事件类型
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
    
    
        // 按事件类型遍历退订相关订阅方法
        for (Class<?> eventType : subscribedTypes) {
    
    
            unsubscribeByEventType(subscriber, eventType);
        }
        // 从订阅者所接收的事件类型Map中移除该订阅者
        typesBySubscriber.remove(subscriber);
    } else {
    
    
        logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}

private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
    
    
    // 获取需要退订的事件类型的订阅者方法
    List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions != null) {
    
    
        // 循环遍历移除当前订阅者的订阅者方法
        int size = subscriptions.size();
        for (int i = 0; i < size; i++) {
    
    
            Subscription subscription = subscriptions.get(i);
            if (subscription.subscriber == subscriber) {
    
    
                subscription.active = false;
                subscriptions.remove(i);
                i--;
                size--;
            }
        }
    }
}

The logic of this method is also relatively simple. It just removes the subscriber and all its associated method objects from the collection.
Although the information about the subscriber will be removed here, the static member variable METHOD_CACHE in the SubscriberMethodFinder will still be The information of registered subscribers is cached, which is also to achieve information reuse when some subscribers register EventBus multiple times successively, and avoid multiple circular reflections.

ask two questions

pit of inheritance

The problem is: if the subclass rewrites multiple Subscribe methods of the parent class, an IllegalStateException will be thrown. Because of what
For example, in the example below. The parent class BaseActivity declares two Subscribe methods, and the subclass MainActivity rewrites these two methods. At this time, an IllegalStateException will be thrown after running. And if MainActivity does not rewrite or only rewrites one method, it can run normally

open class BaseActivity : AppCompatActivity() {
    
    

    @Subscribe
    open fun fun1(msg: String) {
    
    

    }

    @Subscribe
    open fun fun2(msg: String) {
    
    

    }

}

class MainActivity : BaseActivity() {
    
    

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        EventBus.getDefault().register(this)
    }

    override fun onDestroy() {
    
    
        super.onDestroy()
        EventBus.getDefault().unregister(this)
    }

    @Subscribe
    override fun fun1(msg: String) {
    
    

    }

    @Subscribe
    override fun fun2(msg: String) {
    
    

    }

}

Answer: An exception is thrown in the checkAdd method of FindState
1. The resolution direction of the Subscribe method of EventBus is from the subclass to the parent class, and the Subscribe method under the same class is parsed in the order of declaration.
2. When the checkAdd method starts to parse BaseActivity When the fun2 method is used, the existing object is BaseActivity.fun1, and operation 1 will be executed at this time, and since the subclass has rewritten the fun1 method, the checkAddWithMethodSignature method will return false at this time, eventually causing an exception to be thrown

How does EventBus switch between threads?

In EventBus, thread scheduling is performed by using the ThreadMode set by the Subscribe annotation, which is divided into the following situations:

  1. The thread where the POSTING event subscriber and the publisher are located is the same, so there is no need to switch.
  2. MAIN Calls back directly if the publisher is on the main thread, otherwise switches to the main thread internally through the Handler.
  3. MAIN_ORDERED does not distinguish the thread of the publisher, and switches to the main thread internally through the Handler.
  4. Background If the publisher is in the child thread, it will be called back directly, otherwise it will be switched to the child thread for execution through the EventBus internal thread pool.
    • We can customize the thread pool through the EventBusBuilder.executorService(ExecutorService executorService) method. If there is no custom setting, the default thread pool will be used. The default thread pool is created in EventBusBuilder. The code is as follows:
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
  1. ASYNC switches to sub-thread execution through the EventBus internal thread pool.
    • Executors.newCachedThreadPool()

Let’s talk about MAIN and MAIN_ORDERED here.
We know that these two types use mainThreadPoster to send messages.

mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;

Going back to the code, you can see that it was created through mainThreadSupport, so let's see what is going on with mainThreadSupport?
mainThreadSupport

public interface MainThreadSupport {
    
    

    boolean isMainThread();

    Poster createPoster(EventBus eventBus);
}

Implement class DefaultAndroidMainThreadSupport

public class DefaultAndroidMainThreadSupport implements MainThreadSupport {
    
    

    @Override
    public boolean isMainThread() {
    
    
        return Looper.getMainLooper() == Looper.myLooper();
    }

    @Override
    public Poster createPoster(EventBus eventBus) {
    
    
        return new HandlerPoster(eventBus, Looper.getMainLooper(), 10);
    }
}

Main thread switching class HandlerPoster

public class HandlerPoster extends Handler implements Poster {
    
    
    // 事件队列
    private final PendingPostQueue queue;
    // 处理消息最大间隔时间 默认10ms,每次循环发布消息的时间超过该值时,就会让出主线程的使用权,等待下次调度再继续发布事件
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    // 此 Handle 是否活跃
    private boolean handlerActive;

    /**
     * 唯一构造
     *
     * @param eventBus                     EventBus
     * @param looper                       Looper 主线程的 Looper
     * @param maxMillisInsideHandleMessage int 超时时间
     */
    public HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
    
    
    super(looper);
    this.eventBus = eventBus;
    this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
    queue = new PendingPostQueue();
}

    /**
     * 入队
     *
     * @param subscription Subscription 接收事件的订阅方法
     * @param event        Object 将发布给订阅者的事件
     */
    public void enqueue(Subscription subscription, Object event) {
    
    
        // 获取一个 PendingPost,实际上将 subscription、event 包装成为一个 PendingPost
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        // 加锁 监视器为当前对象
        synchronized (this) {
    
    
            // 将获取到的 PendingPost 包装类入队
            queue.enqueue(pendingPost);
            // 判断此发布器是否活跃,如果活跃就不执行,等待 Looper 调度上一个消息,重新进入发布处理
            if (!handlerActive) {
    
    
                // 将发布器设置为活跃状态
                handlerActive = true;
                // sendMessage
                // 划重点!!!
                // 此处没有使用 new Message(),而是使用了 obtainMessage(),该方法将从全局的消息对象池中复用旧的对象,这比直接创建要更高效
                if (!sendMessage(obtainMessage())) {
    
    
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    /**
     * 处理消息
     * 该 Handle 的工作方式为:
     *
     */
    @Override
    public void handleMessage(Message msg) {
    
    
        boolean rescheduled = false;
        try {
    
    
            // 获取一个开始时间
            long started = SystemClock.uptimeMillis();
            // 死循环
            while (true) {
    
    
                // 取出队列中最前面的元素
                PendingPost pendingPost = queue.poll();
                // 接下来会进行两次校验操作
                // 判空 有可能队列中已经没有元素
                if (pendingPost == null) {
    
    
                    // 再次检查,这次是同步的
                    synchronized (this) {
    
    
                        // 继续取队头的元素
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
    
    
                            // 还是为 null,将处理状态设置为不活跃,跳出循环
                            handlerActive = false;
                            return;
                        }
                    }
                }
                // 调用订阅者方法
                eventBus.invokeSubscriber(pendingPost);
                // 获得方法耗时
                long timeInMethod = SystemClock.uptimeMillis() - started;
                // 判断本次调用的方法耗时是否超过预设值
                if (timeInMethod >= maxMillisInsideHandleMessage) {
    
    
                    // 发送进行下一次处理的消息,为了不阻塞主线程,暂时交出主线程使用权,并且发布消息到Looper,等待下一次调度再次进行消息的发布操作
                    if (!sendMessage(obtainMessage())) {
    
    
                        throw new EventBusException("Could not send handler message");
                    }
                    // 设置为活跃状态
                    rescheduled = true;
                    return;
                }
            }
        } finally {
    
    
            // 更新 Handle 状态
            handlerActive = rescheduled;
        }
    }
}

It can be seen that the Handler mechanism is actually used.

Summarize

The summary is, you see the summary. It means that you are destined to become stronger! ! ! ! ! ! ! !

Guess you like

Origin blog.csdn.net/weixin_45112340/article/details/131969781