什么是EventBus

EventBus是通过使用发布者/订阅者模式来实现解耦的Android和Java开源库。在Android开发中通常使用EventBus实现Activities, Fragments, Threads, Services等组件之间的通信。但EventBus不能实现跨进程间的通信。

图文表达



源码剖析

  • UML类图
  • 源码分析 EventBus.java
package de.greenrobot.event;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

/**
 * 
 Class based event bus, optimized for Android. By default, subscribers will handle events in methods named "onEvent".
 *
 * @author Markus Junginger, greenrobot
 */
public class EventBus {
    /**
     * Log tag, apps may override it.
     */
    public static String TAG = "Event";

    private static final EventBus defaultInstance = new EventBus();//默认实例

    public enum ThreadMode {
        /**
         * Subscriber will be called in the same thread, which is posting the event.
         */
        PostThread,//发布事件所在线程订阅
        /**
         * Subscriber will be called in Android's main thread (sometimes referred to as UI thread).
         */
        MainThread,//主线程订阅
        /* BackgroundThread */
    }

    //表示某个类中同一个方法名的所有重载方法。(也就是一个类中所有的订阅方法),缓存,目的:提高性能
    private static final Map<String, List<Method>> methodCache = new HashMap<String, List<Method>>();
    //保存事件类型的所有的事件(包括父类和接口),懒加载的,缓存,目的:了提高性能
    private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<Class<?>, List<Class<?>>>();

    //一个事件类型的所有订阅者:发送事件时使用到(时间复杂度为:O(1))
    //用CopyOnWriteArrayList是为了读取是线程安全的。
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    //一个订阅对象的所有订阅事件:
    // 订阅(register)时是加入
    // 取消订阅(unregister)时使用:获取当前订阅对象的所有订阅事件,然后在订阅事件中将这个订阅者删除。
    private final Map<Object, List<Class<?>>> typesBySubscriber;

    //每个线程的事件队列
    private final ThreadLocal<List<Object>> currentThreadEventQueue = new ThreadLocal<List<Object>>() {
        @Override
        protected List<Object> initialValue() {
            return new ArrayList<Object>();
        }
    };

    //每个线程的队列是否在运转中
    private final ThreadLocal<BooleanWrapper> currentThreadIsPosting = new ThreadLocal<BooleanWrapper>() {
        @Override
        protected BooleanWrapper initialValue() {
            return new BooleanWrapper();
        }
    };

    private String defaultMethodName = "onEvent";

    private PostViaHandler mainThreadPoster;

    public static EventBus getDefault() {
        return defaultInstance;
    }

    public EventBus() {
        subscriptionsByEventType = new HashMap<Class<?>, CopyOnWriteArrayList<Subscription>>();
        typesBySubscriber = new HashMap<Object, List<Class<?>>>();
        mainThreadPoster = new PostViaHandler(Looper.getMainLooper());
    }

    public void register(Object subscriber) {//注册
        register(subscriber, defaultMethodName, ThreadMode.PostThread);//默认方法名,即onEvent,
    }

    public void registerForMainThread(Object subscriber) {
        register(subscriber, defaultMethodName, ThreadMode.MainThread);
    }

    //这里应该加同步synchronized
    public void register(Object subscriber, String methodName, ThreadMode threadMode) {//传入订阅者,遍历查找其订阅的所有事件
        List<Method> subscriberMethods = findSubscriberMethods(subscriber.getClass(), methodName);
        for (Method method : subscriberMethods) {
            Class<?> eventType = method.getParameterTypes()[0];//参数的类型
            //查找的时候是根据参数的类型来确定订阅者的
            subscribe(subscriber, method, eventType, threadMode);
        }
    }

    //如果当前类含有父类,是否查找父类中的所有含指定名称的方法
    private List<Method> findSubscriberMethods(Class<?> subscriberClass, String methodName) {//查找某个类中所有指定名称的方法
        String key = subscriberClass.getName() + '.' + methodName; //类名+方法名为Key

        //key相同的同时进入,会出现两次创建
        List<Method> subscriberMethods;
        synchronized (methodCache) {
            subscriberMethods = methodCache.get(key);//方法名称一样的存在多个重载方法
        }
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
        //同时进入
        subscriberMethods = new ArrayList<Method>();
        Class<?> clazz = subscriberClass;
        HashSet<Class<?>> eventTypesFound = new HashSet<Class<?>>();// 同一个类参数相同的方法只加入一次(就是重写的方法)
        while (clazz != null) {
            String name = clazz.getName();
            if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {//过滤掉系统类
                // Skip system classes, this just degrades performance
                break;
            }


            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    if (parameterTypes.length == 1) {//参数为1个
                        if (eventTypesFound.add(parameterTypes[0])) {
                            // Only add if not already found in a sub class
                            subscriberMethods.add(method);
                        }
                    }
                }
            }
            clazz = clazz.getSuperclass();//查找父类,也就是父类方法也会被调用
        }
        if (subscriberMethods.isEmpty()) {//没有订阅方法,抛出异常
            throw new RuntimeException("Subscriber " + subscriberClass + " has no methods called " + methodName);
        } else {
            synchronized (methodCache) {
                methodCache.put(key, subscriberMethods);
            }
            return subscriberMethods;
        }
    }

    public void register(Object subscriber, Class<?> eventType, Class<?>... moreEventTypes) {//指定事件类型
        register(subscriber, defaultMethodName, ThreadMode.PostThread, eventType, moreEventTypes);
    }

    public void registerForMainThread(Object subscriber, Class<?> eventType, Class<?>... moreEventTypes) {//指定事件类型注册
        register(subscriber, defaultMethodName, ThreadMode.MainThread, eventType, moreEventTypes);
    }

    public synchronized void register(Object subscriber, String methodName, ThreadMode threadMode, Class<?> eventType,
                                      Class<?>... moreEventTypes) {
        Class<?> subscriberClass = subscriber.getClass();
        Method method = findSubscriberMethod(subscriberClass, methodName, eventType);
        subscribe(subscriber, method, eventType, threadMode);

        for (Class<?> anothereventType : moreEventTypes) {
            method = findSubscriberMethod(subscriberClass, methodName, anothereventType);
            subscribe(subscriber, method, anothereventType, threadMode);
        }
    }

    //应该在对象lock中调用
    private void subscribe(Object subscriber, Method subscriberMethod, Class<?> eventType, ThreadMode threadMode) {
        //调用方:register(Object subscriber, String methodName, ThreadMode threadMode)没有加锁
        //并发的问题:多个线程同时进入,不同页面都含有同一事件
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<Subscription>();
            subscriptionsByEventType.put(eventType, subscriptions);//事件类型为key,订阅者为value,一对多
        } else {
            for (Subscription subscription : subscriptions) {//同一事件的订阅者,多次设置
                if (subscription.subscriber == subscriber) {
                    throw new RuntimeException("Subscriber " + subscriber.getClass() + " already registered to event "
                            + eventType);
                }
            }
        }

        subscriberMethod.setAccessible(true);
        Subscription subscription = new Subscription(subscriber, subscriberMethod, threadMode);
        subscriptions.add(subscription);

        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);//订阅者为key,订阅的事件为value,一对多
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<Class<?>>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);
    }

    /**
     * Class.getMethod is slow on Android 2.3 (and probably other versions), so use getDeclaredMethod and go up in the
     * class hierarchy if neccessary.
     */
    private Method findSubscriberMethod(Class<?> subscriberClass, String methodName, Class<?> eventType) {
        Class<?> clazz = subscriberClass;
        while (clazz != null) {
            try {
                return clazz.getDeclaredMethod(methodName, eventType);
            } catch (NoSuchMethodException ex) {
                clazz = clazz.getSuperclass();
            }
        }
        throw new RuntimeException("Method " + methodName + " not found  in " + subscriberClass
                + " (must have single parameter of event type " + eventType + ")");
    }

    /**
     * Unregisters the given subscriber for the given event classes.
     */
    public synchronized void unregister(Object subscriber, Class<?>... eventTypes) {
        if (eventTypes.length == 0) {
            throw new IllegalArgumentException("Provide at least one event class");
        }
        List<Class<?>> subscribedClasses = typesBySubscriber.get(subscriber);
        if (subscribedClasses != null) {
            for (Class<?> eventType : eventTypes) {
                unubscribeByEventType(subscriber, eventType);
                subscribedClasses.remove(eventType);
            }
            if (subscribedClasses.isEmpty()) {
                typesBySubscriber.remove(subscriber);
            }
        } else {
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

    /**
     * Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber.
     */
    private void unubscribeByEventType(Object subscriber, Class<?> eventType) {
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();
            for (int i = 0; i < size; i++) {
                if (subscriptions.get(i).subscriber == subscriber) {
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

    /**
     * Unregisters the given subscriber from all event classes.
     */
    public synchronized void unregister(Object subscriber) {
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);//删除所有的订阅事件
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                unubscribeByEventType(subscriber, eventType);//删除事件类型
            }
            typesBySubscriber.remove(subscriber);
        } else {
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

    //post(Object event)
    //post(Object event)
    /**
     * Posts the given event to the event bus.
     */
    public void post(Object event) {//String Object
        List<Object> eventQueue = currentThreadEventQueue.get(); //每个线程一个队列,保证同一个线程发送事件的有序性
        eventQueue.add(event);

        BooleanWrapper isPosting = currentThreadIsPosting.get();
        if (isPosting.value) {//当前线程队列正在运转
            return;
        } else {//没有运转开始运转
            isPosting.value = true;
            try {
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0)); //开始发送事件
                }
            } finally {
                isPosting.value = false;
            }
        }
    }

    private void postSingleEvent(Object event) throws Error {

        List<Class<?>> eventTypes = findEventTypes(event.getClass()); //找到所有的事件类型(需要给父事件和接口事件也发送)
        boolean subscriptionFound = false;
        int countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
            Class<?> clazz = eventTypes.get(h);
            CopyOnWriteArrayList<Subscription> subscriptions;
            synchronized (this) {//只能保证Map的原子性
                subscriptions = subscriptionsByEventType.get(clazz);
            }

            if (subscriptions != null) {
                for (Subscription subscription : subscriptions) {//因为是CopyOnWriteArrayList,所以写入时读取是线程安全的
                    if (subscription.threadMode == ThreadMode.PostThread) {//在发送线程中执行
                        postToSubscribtion(subscription, event);
                    } else if (subscription.threadMode == ThreadMode.MainThread) {//在主线程中执行
                        mainThreadPoster.enqueue(event, subscription);//在主线程中执行
                    } else {
                        throw new IllegalStateException("Unknown thread mode: " + subscription.threadMode);
                    }
                }
                subscriptionFound = true;
            }
        }
        if (!subscriptionFound) {
            Log.d(TAG, "No subscripers registered for event " + event.getClass());
        }
    }

    //查找所有的事件类型:当前类型和所有父类型,所有接口,包括父类型
    //

    /**
     * Finds all Class objects including super classes and interfaces.
     */
    private List<Class<?>> findEventTypes(Class<?> eventClass) {
        synchronized (eventTypesCache) {
            List<Class<?>> eventTypes = eventTypesCache.get(eventClass); //缓存中存在,直接返回
            if (eventTypes == null) {
                eventTypes = new ArrayList<Class<?>>();
                Class<?> clazz = eventClass;
                while (clazz != null) {//事件类型,父事件
                    eventTypes.add(clazz); //本身是一个事件类型
                    addInterfaces(eventTypes, clazz.getInterfaces());
                    clazz = clazz.getSuperclass();
                }
                eventTypesCache.put(eventClass, eventTypes);
            }
            return eventTypes;
        }
    }

    /**
     * Recurses through super interfaces.
     */
    static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {
        for (Class<?> interfaceClass : interfaces) {
            if (!eventTypes.contains(interfaceClass)) {
                eventTypes.add(interfaceClass);
                addInterfaces(eventTypes, interfaceClass.getInterfaces());
            }
        }
    }

    static void postToSubscribtion(Subscription subscription, Object event) throws Error {
        try {
            subscription.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            Throwable cause = e.getCause();
            Log.e(TAG, "Could not dispatch event: " + event.getClass() + " to subscribing class "
                    + subscription.subscriber.getClass(), cause);
            if (cause instanceof Error) {
                throw (Error) cause;
            }
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }

    final static class Subscription {
        final Object subscriber;
        final Method method;
        final ThreadMode threadMode;

        Subscription(Object subscriber, Method method, ThreadMode threadMode) {
            this.subscriber = subscriber;
            this.method = method;
            this.threadMode = threadMode;
        }

        @Override
        public boolean equals(Object other) {
            if (other instanceof Subscription) {
                Subscription otherSubscription = (Subscription) other;
                // Super slow (improve once used): http://code.google.com/p/android/issues/detail?id=7811
                return subscriber == otherSubscription.subscriber && method.equals(otherSubscription.method);
            } else {
                return false;
            }
        }

        @Override
        public int hashCode() {
            // Check performance once used
            return subscriber.hashCode() + method.hashCode();
        }
    }

    /**
     * For ThreadLocal, much faster to set than storing a new Boolean.
     */
    final static class BooleanWrapper {//提高性能,使用Boolean,修改值时需要每次set
        boolean value;
    }

    final static class PostViaHandler extends Handler {//主线程发送队列

        PostViaHandler(Looper looper) {
            super(looper);
        }

        void enqueue(Object event, Subscription subscription) {
            PendingPost pendingPost = PendingPost.obtainPendingPost(event, subscription); //待发送对象
            Message message = obtainMessage();
            message.obj = pendingPost;
            if (!sendMessage(message)) {//发送失败:usually because the looper processing the message queue is exiting.
                throw new RuntimeException("Could not send handler message");
            }
        }

        @Override
        public void handleMessage(Message msg) {
            PendingPost pendingPost = (PendingPost) msg.obj;
            Object event = pendingPost.event;
            Subscription subscription = pendingPost.subscription;
            PendingPost.releasePendingPost(pendingPost);
            postToSubscribtion(subscription, event);
        }

    }

}
复制代码

PendingPost.java

package de.greenrobot.event;

import java.util.ArrayList;
import java.util.List;

import de.greenrobot.event.EventBus.Subscription;

final class PendingPost {//使用了享元模式
    private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();

    Object event;
    Subscription subscription;

    private PendingPost(Object event, Subscription subscription) {
        this.event = event;
        this.subscription = subscription;
    }

    static PendingPost obtainPendingPost(Object event, Subscription subscription) {
        synchronized (pendingPostPool) {
            int size = pendingPostPool.size();
            if (size > 0) {
                PendingPost pendingPost = pendingPostPool.remove(size - 1);
                pendingPost.event = event;
                pendingPost.subscription = subscription;
                return pendingPost;
            }
        }
        return new PendingPost(event, subscription);
    }

    static void releasePendingPost(PendingPost pendingPost) {
        synchronized (pendingPostPool) {
            pendingPostPool.add(pendingPost);
        }
    }

}
复制代码
  • 优点
    1.在作者的注释中(Class based event bus[指Google guava库中的 event bus], optimized for Android. By default, subscribers will handle events in methods named "onEvent".)可以看到,为了优化性能,弃用了注解,使用固定或指定订阅方法的方式,
    2.轻巧,不依赖Context。一些处理细节上也做了相应的优化,如:使用BooleanWrapper代替Boolean,这样就不需要每次更改值都调用ThreadLocal的set方法;PendingPost的创建采用了享元模式提高了获取其实例的性能,不需要频繁创建和销毁;利用CopyOnWriteArrayList在写入安全的情况下提高了读取性能。
    3.能指定在主线程中订阅事件。因为通常情况下,我们会在非UI线程中发送事件来更新UI,而更新UI需要在主线程中执行。
  • 不足
    1.为了性能最求性能的极致,失去了订阅方法的灵活性,只能指定onEvent方法才能监听,或者注册时调用指定方法名,没有使用注解那么灵活。
    2.订阅者接收事件的线程不能根据订阅事件设置。因为经常我们在一个类中会订阅多个事件,而每个事件基本上是没有相关性的,在哪个线程上订阅是根据事件本身来决定的。
    3、强制使用事件的传递性,如:我们发送某个事件,那么这个事件所有的父类及接口都会被强制触发,最好有设置开关,让用户决定。
  • 解读
  • 以下代码为何需要使用事件队列,直接发送事件给订阅者不是更快更直接吗?
public void post(Object event) {//String Object
    List<Object> eventQueue = currentThreadEventQueue.get(); //每个线程一个队列,保证同一个线程发送事件的有序性
    eventQueue.add(event);

    BooleanWrapper isPosting = currentThreadIsPosting.get();
    if (isPosting.value) {//当前线程队列正在运转
        //在同一个线程中什么时候会走到这里呢?如果走不到这里那么这个队列就没有意义
        return;
    } else {//没有运转开始运转
        isPosting.value = true;
        try {
            while (!eventQueue.isEmpty()) {
                postSingleEvent(eventQueue.remove(0)); //开始发送事件
            }
        } finally {
            isPosting.value = false;
        }
    }
}

如果我们能找到队列正在运转的情况下,那么队列就有意义,能保证事件处理的有序性。

举例:
public class RefreshEvent {}
public class Activity1 extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onDestroy() {
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }
    
    public void onEvent(TestEvent event) {
        EventBus.getDefault().post(new RefreshEvent());
    }
}

public class ActivityB extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onDestroy() {
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }
    
    public void onEvent(TestEvent event) {
        
    }
}

我们在后台业务方法中发送了刷新事件:
EventBus.getDefault().post(new RefreshEvent());

上面的例子中:1、一个事件被多个订阅者订阅;2、订阅者收到事件后再次发送相同事件。

在这种情况下,如果我们不使用队列,那么在同一个线程中,先发送的事件订阅者就可能会被后收到。
这里使用ThreadLocal+队列,就很巧妙地维护了在同一个线程中事件处理的有序性。

复制代码
  • bug
    public void register(Object subscriber, String methodName, ThreadMode threadMode) 方法存在线程安全的问题,除非调用者都加了锁,但代码中最常用的调用public void register(Object subscriber, String methodName, ThreadMode threadMode)却没有加锁。

自实现

  • 第一步,实现主逻辑:
  • 消息的订阅:register(Object subscriber)
  • 消息的发布:post(Object event)
  • 取消订阅:unregister(Object subscriber)

EventBus.java 代码

package org.hjb.eventbus;

import android.util.Log;

import androidx.annotation.NonNull;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

public class EventBus {

    private static final String TAG = "EventBus";

    private static volatile EventBus mDefaultEventBus;

    private static final String DEFAULT_METHOD_NAME = "onEvent";

    //key:订阅事件
    //value:订阅者信息,订阅者信息包括:订阅对象,订阅方法
    private final HashMap<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType = new HashMap<>();

    private ThreadLocal<ArrayList<Object>> currentThreadEventQueue = new ThreadLocal<ArrayList<Object>>() {
        @Override
        protected ArrayList<Object> initialValue() {
            return new ArrayList<>();
        }
    };

    private ThreadLocal<Boolean> currentThreadIsPosting = new ThreadLocal<Boolean>() {
        @Override
        protected Boolean initialValue() {
            return Boolean.FALSE;
        }
    };

    public EventBus() {
    }

    public static EventBus getDefault() {
        if (mDefaultEventBus == null) {
            synchronized (EventBus.class) {
                if (mDefaultEventBus == null) {
                    mDefaultEventBus = new EventBus();
                }
            }
        }

        return mDefaultEventBus;
    }

    /**
     * 订阅
     *
     * @param subscriber 订阅者
     */
    public synchronized void register(@NonNull Object subscriber) {//订阅
        //保存当前订阅者的所有订阅事件
        //因为查询是通过订阅事件来查找的,所以使用map来保存订阅数据

        //查找当前订阅对象的所有订阅方法
        ArrayList<Method> methods = findSubscriberMethods(subscriber, DEFAULT_METHOD_NAME);

        for (Method method : methods) {
            //订阅事件
            Class<?> eventType = method.getParameterTypes()[0];

            CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
            if (subscriptions == null) {
                subscriptions = new CopyOnWriteArrayList<>();
                subscriptionsByEventType.put(eventType, subscriptions);
            } else { //需要判断是否重复添加(同一个事件已经加过订阅者),抛出异常

                for (Subscription subscription : subscriptions) {
                    if (subscription.subscriber == subscriber) {
                        throw new RuntimeException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
                    }
                }

            }

            method.setAccessible(true);//防止私有方法不能访问
            subscriptions.add(new Subscription(subscriber, method));

        }
    }

    /**
     * 需要查找当前对象所有带onEvent的重载方法,包括父类
     * <p>
     * 注意点:
     * 1、覆盖的方法不要重复添加
     * 2、过滤掉系统类,java/javax/android开头的
     * 3、只查找单个参数的方法
     * 4、私有方法也查找
     *
     * @param subscriber 订阅者
     * @return 所有订阅对象
     */
    private ArrayList<Method> findSubscriberMethods(Object subscriber, String methodName) {

        ArrayList<Method> subscriberMethods = new ArrayList<>();

        Class<?> clazz = subscriber.getClass();

        while (clazz != null) {
            //过滤系统类
            String name = clazz.getName();
            if (name.startsWith("java") || name.startsWith("javax") || name.startsWith("android")) {
                break;
            }
            //查找目标方法
            for (Method method : clazz.getDeclaredMethods()) {

                if (method.getName().equals(methodName) && method.getParameterTypes().length == 1) {

                    int i = 0, size = subscriberMethods.size();

                    for (; i < size; i++) {
                        if (subscriberMethods.get(i).getParameterTypes()[0].equals(method.getParameterTypes()[0])) {
                            break;
                        }
                    }

                    if (i == size) {//表示不存在,加入
                        subscriberMethods.add(method);
                    }

                }
            }

            clazz = clazz.getSuperclass();

        }

        return subscriberMethods;
    }

    /**
     * 发送事件
     * <p>
     * 需要给所有订阅者发送事件
     * <p>
     * 注意:我们要发送的不仅是当前对象的订阅者,同时包括当前父类对象和接口对象的订阅者。
     * <p>
     * 解决有有序性的问题:我们需要保证同一个线程中
     *
     * @param event 事件
     */
    public void post(Object event) {

        List<Object> eventQueue = currentThreadEventQueue.get();
        eventQueue.add(event);

        Boolean isPosting = currentThreadIsPosting.get();
        if (!isPosting.booleanValue()) {
            currentThreadIsPosting.set(Boolean.TRUE);

            while (!eventQueue.isEmpty()) {
                postEvent(eventQueue.remove(0));
            }

            currentThreadIsPosting.set(Boolean.FALSE);
        } else {
            Log.i("hejunbin", "正在运转");
        }
    }

    /**
     * 发送事件
     *
     * @param event 待发送事件
     */
    private void postEvent(Object event) {
        //1、找到当前对象的所有事件类型
        ArrayList<Class<?>> eventTypes = findEventTypes(event.getClass());

        //2、找到此事件所有的订阅者
        boolean subscriptionFound = false; //是否找到了订阅者

        for (Class<?> eventType : eventTypes) {

            CopyOnWriteArrayList<Subscription> subscriptions;

            synchronized (this) {
                subscriptions = subscriptionsByEventType.get(eventType);
            }

            if (subscriptions != null && subscriptions.size() > 0) {
                subscriptionFound = true;

                for (Subscription subscription : subscriptions) {
                    try {
                        subscription.method.invoke(subscription.subscriber, event);
                    } catch (Exception e) {
                        Log.e(TAG, "Could not dispatch event: " + event.getClass() + " to subscribing class " + subscription.subscriber.getClass(), e.getCause());
                    }
                }

            }

        }

        if (!subscriptionFound) {
            Log.d(TAG, "No subscripers registered for event " + event.getClass());
        }
    }

    /**
     * 找到当前对象的所有事件类型(包括父类和接口)
     *
     * @param eventClass 事件类型
     * @return 所有事件类型
     */
    private ArrayList<Class<?>> findEventTypes(Class<?> eventClass) {

        ArrayList<Class<?>> eventTypes = new ArrayList<>();

        Class<?> clazz = eventClass;

        while (clazz != null) {
            eventTypes.add(clazz);
            //接口本身本身存在层级
            addInterfaces(eventTypes, clazz.getInterfaces());
            clazz = clazz.getSuperclass();
        }

        return eventTypes;
    }

    private void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {
        for (Class<?> interfaceClass : interfaces) {
            if (!eventTypes.contains(interfaceClass)) {
                eventTypes.add(interfaceClass);
                addInterfaces(eventTypes, interfaceClass.getInterfaces());
            }
        }
    }

    /**
     * 取消订阅
     *
     * @param subscriber 订阅者
     */
    public synchronized void unregister(Object subscriber) {//取消订阅

        for (Map.Entry<Class<?>, CopyOnWriteArrayList<Subscription>> entry : subscriptionsByEventType.entrySet()) {
            int size = entry.getValue().size();

            for (int i = 0; i < size; i++) {
                if (entry.getValue().get(i).subscriber == subscriber) {
                    entry.getValue().remove(i);
                    i--;
                    size--;
                }
            }
        }

    }

    /**
     * 订阅对象
     */
    static class Subscription {
        Object subscriber;

        Method method;

        public Subscription(Object subscriber, Method method) {
            this.subscriber = subscriber;
            this.method = method;
        }
    }
}

复制代码
  • 可以在主线程中订阅事件
    在Android利用Handler的机制,将事件发送到主队列中执行。
    因为需要将订阅信息(Subscription)和事件(event)都需要传递,而Handler中的Message只能传递单个Object,所以自己创建了PendingPost包装类。
    EventBus.java代码
package org.hjb.eventbus;


import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import androidx.annotation.MainThread;
import androidx.annotation.NonNull;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

public class EventBus {

    private static final String TAG = "EventBus";

    private static volatile EventBus mDefaultEventBus;

    private static final String DEFAULT_METHOD_NAME = "onEvent";

    public enum ThreadMode {
        PostThread, //post所在线程
        MainThread,//主线程
    }

    //key:订阅事件
    //value:订阅者信息,订阅者信息包括:订阅对象,订阅方法
    private final HashMap<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType = new HashMap<>();

    private ThreadLocal<ArrayList<Object>> currentThreadEventQueue = new ThreadLocal<ArrayList<Object>>() {
        @Override
        protected ArrayList<Object> initialValue() {
            return new ArrayList<>();
        }
    };

    private ThreadLocal<Boolean> currentThreadIsPosting = new ThreadLocal<Boolean>() {
        @Override
        protected Boolean initialValue() {
            return Boolean.FALSE;
        }
    };

    private MainThreadHandler mainThreadHandler;

    public EventBus() {
        mainThreadHandler = new MainThreadHandler();
    }

    public static EventBus getDefault() {
        if (mDefaultEventBus == null) {
            synchronized (EventBus.class) {
                if (mDefaultEventBus == null) {
                    mDefaultEventBus = new EventBus();
                }
            }
        }

        return mDefaultEventBus;
    }

    /**
     * 订阅
     *
     * @param subscriber 订阅者
     */
    public synchronized void register(@NonNull Object subscriber) {//订阅
        subscribe(subscriber, ThreadMode.PostThread);
    }

    public synchronized void registerForMainThread(Object subscriber) {
        subscribe(subscriber, ThreadMode.MainThread);
    }

    public synchronized void register(Object subscriber, ThreadMode mode) {
        subscribe(subscriber, mode);
    }

    private void subscribe(Object subscriber, ThreadMode mode) {//需要在线程安全的方法中调用
        //保存当前订阅者的所有订阅事件
        //因为查询是通过订阅事件来查找的,所以使用map来保存订阅数据

        //查找当前订阅对象的所有订阅方法
        ArrayList<Method> methods = findSubscriberMethods(subscriber, DEFAULT_METHOD_NAME);

        for (Method method : methods) {
            //订阅事件
            Class<?> eventType = method.getParameterTypes()[0];

            CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
            if (subscriptions == null) {
                subscriptions = new CopyOnWriteArrayList<>();
                subscriptionsByEventType.put(eventType, subscriptions);
            } else { //需要判断是否重复添加(同一个事件已经加过订阅者),抛出异常

                for (Subscription subscription : subscriptions) {
                    if (subscription.subscriber == subscriber) {
                        throw new RuntimeException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
                    }
                }

            }

            method.setAccessible(true);//防止私有方法不能访问
            subscriptions.add(new Subscription(subscriber, method, mode));

        }
    }


    /**
     * 需要查找当前对象所有带onEvent的重载方法,包括父类
     * <p>
     * 注意点:
     * 1、覆盖的方法不要重复添加
     * 2、过滤掉系统类,java/javax/android开头的
     * 3、只查找单个参数的方法
     * 4、私有方法也查找
     *
     * @param subscriber 订阅者
     * @return 所有订阅对象
     */
    private ArrayList<Method> findSubscriberMethods(Object subscriber, String methodName) {

        ArrayList<Method> subscriberMethods = new ArrayList<>();

        Class<?> clazz = subscriber.getClass();

        while (clazz != null) {
            //过滤系统类
            String name = clazz.getName();
            if (name.startsWith("java") || name.startsWith("javax") || name.startsWith("android")) {
                break;
            }
            //查找目标方法
            for (Method method : clazz.getDeclaredMethods()) {

                if (method.getName().equals(methodName) && method.getParameterTypes().length == 1) {

                    int i = 0, size = subscriberMethods.size();

                    for (; i < size; i++) {
                        if (subscriberMethods.get(i).getParameterTypes()[0].equals(method.getParameterTypes()[0])) {
                            break;
                        }
                    }

                    if (i == size) {//表示不存在,加入
                        subscriberMethods.add(method);
                    }

                }
            }

            clazz = clazz.getSuperclass();

        }

        return subscriberMethods;
    }

    /**
     * 发送事件
     * <p>
     * 需要给所有订阅者发送事件
     * <p>
     * 注意:我们要发送的不仅是当前对象的订阅者,同时包括当前父类对象和接口对象的订阅者。
     * <p>
     * 解决有有序性的问题:我们需要保证同一个线程中
     *
     * @param event 事件
     */
    public void post(Object event) {

        List<Object> eventQueue = currentThreadEventQueue.get();
        eventQueue.add(event);

        Boolean isPosting = currentThreadIsPosting.get();
        if (!isPosting.booleanValue()) {
            currentThreadIsPosting.set(Boolean.TRUE);

            while (!eventQueue.isEmpty()) {
                postEvent(eventQueue.remove(0));
            }

            currentThreadIsPosting.set(Boolean.FALSE);
        } else {
            Log.i("hejunbin", "正在运转");
        }
    }

    /**
     * 发送事件
     *
     * @param event 待发送事件
     */
    private void postEvent(Object event) {
        //1、找到当前对象的所有事件类型
        ArrayList<Class<?>> eventTypes = findEventTypes(event.getClass());

        //2、找到此事件所有的订阅者
        boolean subscriptionFound = false; //是否找到了订阅者

        for (Class<?> eventType : eventTypes) {

            CopyOnWriteArrayList<Subscription> subscriptions;

            synchronized (this) {
                subscriptions = subscriptionsByEventType.get(eventType);
            }

            if (subscriptions != null && subscriptions.size() > 0) {
                subscriptionFound = true;

                for (Subscription subscription : subscriptions) {

                    if (subscription.mode == ThreadMode.PostThread) {
                        postEvent(subscription, event);
                    } else if (subscription.mode == ThreadMode.MainThread) {//在主线程中发送
                        mainThreadHandler.enqueue(subscription, event);
                    } else {//非法
                        throw new IllegalStateException("Unknown thread mode: " + subscription.mode);
                    }

                }

            }

        }

        if (!subscriptionFound) {
            Log.d(TAG, "No subscripers registered for event " + event.getClass());
        }
    }

    private static void postEvent(Subscription subscription, Object event) {

        try {
            subscription.method.invoke(subscription.subscriber, event);
        } catch (Exception e) {
            Log.e(TAG, "Could not dispatch event: " + event.getClass() + " to subscribing class " + subscription.subscriber.getClass(), e.getCause());
        }
    }


    /**
     * 找到当前对象的所有事件类型(包括父类和接口)
     *
     * @param eventClass 事件类型
     * @return 所有事件类型
     */
    private ArrayList<Class<?>> findEventTypes(Class<?> eventClass) {

        ArrayList<Class<?>> eventTypes = new ArrayList<>();

        Class<?> clazz = eventClass;

        while (clazz != null) {
            eventTypes.add(clazz);
            //接口本身本身存在层级
            addInterfaces(eventTypes, clazz.getInterfaces());
            clazz = clazz.getSuperclass();
        }

        return eventTypes;
    }

    private void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {
        for (Class<?> interfaceClass : interfaces) {
            if (!eventTypes.contains(interfaceClass)) {
                eventTypes.add(interfaceClass);
                addInterfaces(eventTypes, interfaceClass.getInterfaces());
            }
        }
    }

    /**
     * 取消订阅
     *
     * @param subscriber 订阅者
     */
    public synchronized void unregister(Object subscriber) {//取消订阅

        for (Map.Entry<Class<?>, CopyOnWriteArrayList<Subscription>> entry : subscriptionsByEventType.entrySet()) {
            int size = entry.getValue().size();

            for (int i = 0; i < size; i++) {
                if (entry.getValue().get(i).subscriber == subscriber) {
                    entry.getValue().remove(i);
                    i--;
                    size--;
                }
            }
        }

    }

    /**
     * 订阅对象
     */
    static class Subscription {
        Object subscriber;

        Method method;

        ThreadMode mode;

        public Subscription(Object subscriber, Method method, ThreadMode mode) {
            this.subscriber = subscriber;
            this.method = method;
            this.mode = mode;
        }
    }

    static class MainThreadHandler extends Handler {

        MainThreadHandler() {
            super(Looper.getMainLooper());
        }

        void enqueue(Subscription subscription, Object event) {
            Message message = Message.obtain();
            message.obj = new PendingPost(subscription, event);
            //现在有两个对象需要传递,但Message只能传递单个对象,而Java没有元祖类型,所以需要自己创建对象或者放入数组中

            if (!sendMessage(message)) {//发送失败:usually because the looper processing the message queue is exiting.
                throw new RuntimeException("Could not send handler message");
            }
        }

        @Override
        public void handleMessage(Message msg) {
            PendingPost pendingPost = (PendingPost) msg.obj;
            postEvent(pendingPost.subscription, pendingPost.event);
        }
    }
}

复制代码

PendingPost.java代码

package de.greenrobot.event;

import java.util.ArrayList;
import java.util.List;

import de.greenrobot.event.EventBus.Subscription;

final class PendingPost {
    Object event;
    Subscription subscription;

    PendingPost(Object event, Subscription subscription) {
        this.event = event;
        this.subscription = subscription;
}
复制代码
  • 性能优化
  • findSubscriberMethods 每次都要循环遍历查找,可以第一次查找后缓存起来,下次直接从缓存中获取。(我们经常在进入页面时register,在返回页面时unregister,当第二次进入时就可以使用缓存中获取了)
    实现代码为:
private static final Map<String, ArrayList<Method>> methodCache = new HashMap<>();
 /**
 * 需要查找当前对象所有带onEvent的重载方法,包括父类
 * <p>
 * 注意点:
 * 1、覆盖的方法不要重复添加
 * 2、过滤掉系统类,java/javax/android开头的
 * 3、只查找单个参数的方法
 * 4、私有方法也查找
 *
 * @param subscriberClass 订阅者类
 * @return 所有订阅对象
 */
private ArrayList<Method> findSubscriberMethods(Class<?> subscriberClass, String methodName) {

    String key = subscriberClass.getName() + '.' + methodName; //类名+方法名为Key

    ArrayList<Method> subscriberMethods = methodCache.get(key);

    if (subscriberMethods != null) {
        return subscriberMethods;
    }

    synchronized (methodCache) {

        subscriberMethods = methodCache.get(key);

        if (subscriberMethods != null) {
            return subscriberMethods;
        }


        subscriberMethods = new ArrayList<>();

        Class<?> clazz = subscriberClass;

        while (clazz != null) {
            //过滤系统类
            String name = clazz.getName();
            if (name.startsWith("java") || name.startsWith("javax") || name.startsWith("android")) {
                break;
            }
            //查找目标方法
            for (Method method : clazz.getDeclaredMethods()) {

                if (method.getName().equals(methodName) && method.getParameterTypes().length == 1) {

                    int i = 0, size = subscriberMethods.size();

                    for (; i < size; i++) {
                        if (subscriberMethods.get(i).getParameterTypes()[0].equals(method.getParameterTypes()[0])) {
                            break;
                        }
                    }

                    if (i == size) {//表示不存在,加入
                        subscriberMethods.add(method);
                    }

                }
            }

            clazz = clazz.getSuperclass();

        }

        if (subscriberMethods.isEmpty()) {//没有订阅方法,抛出异常
            throw new RuntimeException("Subscriber " + subscriberClass + " has no methods called " + methodName);
        } else {
            methodCache.put(key, subscriberMethods);
            return subscriberMethods;
        }
    }

}
复制代码
  • findEventTypes 每次发送事件都会调用,而内部实现也需要循环遍历,也可以通过缓存来提高性能。
    修改代码为:
private static final Map<Class<?>, ArrayList<Class<?>>> eventTypesCache = new HashMap<>();

/**
 * 找到当前对象的所有事件类型(包括父类和接口)
 *
 * @param eventClass 事件类型
 * @return 所有事件类型
 */
private ArrayList<Class<?>> findEventTypes(Class<?> eventClass) {

    ArrayList<Class<?>> eventTypes = eventTypesCache.get(eventClass);

    if (eventTypes != null) {
        return eventTypes;
    }

    synchronized (eventTypesCache) {

        eventTypes = eventTypesCache.get(eventClass);

        if (eventTypes != null) {
            return eventTypes;
        }

        eventTypes = new ArrayList<>();

        Class<?> clazz = eventClass;

        while (clazz != null) {
            eventTypes.add(clazz);
            //接口本身本身存在层级
            addInterfaces(eventTypes, clazz.getInterfaces());
            clazz = clazz.getSuperclass();
        }

        eventTypesCache.put(eventClass, eventTypes);

        return eventTypes;
    }
}
复制代码
  • unregister方法,不管有没有订阅过,都需要双层遍历,时间复杂度为O(n2),可以建立以subscriber为key的哈希表,将时间复杂度降为O(n)。
    修改代码为:
//存储一个订阅对象的所有订阅事件(key:订阅对象,value:所有订阅事件)
private final HashMap<Object, List<Class<?>>> eventTypesBySubscriber = new HashMap<>();

private void subscribe(Object subscriber, ThreadMode mode) {//需要在线程安全的方法中调用
    //保存当前订阅者的所有订阅事件
    //因为查询是通过订阅事件来查找的,所以使用map来保存订阅数据

    //查找当前订阅对象的所有订阅方法
    ArrayList<Method> methods = findSubscriberMethods(subscriber.getClass(), DEFAULT_METHOD_NAME);

    for (Method method : methods) {
        //订阅事件
        Class<?> eventType = method.getParameterTypes()[0];

        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else { //需要判断是否重复添加(同一个事件已经加过订阅者),抛出异常

            for (Subscription subscription : subscriptions) {
                if (subscription.subscriber == subscriber) {
                    throw new RuntimeException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
                }
            }

        }

        method.setAccessible(true);//防止私有方法不能访问
        subscriptions.add(new Subscription(subscriber, method, mode));

        //订阅对象的所订阅的数据类型
        List<Class<?>> subscribedEvents = eventTypesBySubscriber.get(subscriber);//订阅者为key,订阅的事件为value,一对多
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            eventTypesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);

    }
}

/**
 * 取消订阅
 *
 * @param subscriber 订阅者
 */
public synchronized void unregister(Object subscriber) {//取消订阅

    List<Class<?>> eventTypes = eventTypesBySubscriber.get(subscriber);
    if (eventTypes == null) {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        return;
    }

    for (Class<?> eventType : eventTypes) { //虽然这里也是循环,但是这里的只是单个订阅者中的事件,而不是全局的事件的遍历
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size =subscriptions.size();
            for (int i = 0; i < size; i++) {
                if (subscriptions.get(i).subscriber == subscriber) {
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }
    eventTypesBySubscriber.remove(subscriber);
}

复制代码
  • PendingPost使用享元模式(重复利用对象)
    修改代码为:
package org.hjb.eventbus;

import java.util.ArrayList;
import java.util.List;

import org.hjb.eventbus.EventBus.Subscription;

public class PendingPost { //使用了享元模式

    private static final List<PendingPost> pendingPostPool = new ArrayList<>(0);

    Subscription subscription;

    Object event;

    private PendingPost(EventBus.Subscription subscription, Object event) {
        this.subscription = subscription;
        this.event = event;
    }

    static PendingPost obtain(Subscription subscription, Object event) {
        synchronized (pendingPostPool) {//看池子里是否有对象,如果有,使用池子里但对象
//            if (!pendingPostPool.isEmpty()) {
//                PendingPost pendingPost = pendingPostPool.remove(0);
//                pendingPost.subscription = subscription;
//                pendingPost.event = event;
//                return pendingPost;
//            }

            //上面注释的代码使用第一个元素,应该使用最后一个元素,
            //因为使用的是数组存储,如果remove第一个的话,那么每次取出的操作都涉及到数组的搬移操作时间复杂度为O(n)
            //如果删除最后一个元素,不涉及搬移操作时间复杂度为O(1)
            //所以应该写成
            int size = pendingPostPool.size();
            if (size > 0) {
                PendingPost pendingPost = pendingPostPool.remove(size - 1);
                pendingPost.subscription = subscription;
                pendingPost.event = event;

                return pendingPost;
            }
        }

        return new PendingPost(subscription, event);//没有,创建
    }

    void recycle() {
        synchronized (pendingPostPool) {
            pendingPostPool.add(this);
        }
    }
}

复制代码

使用时也需要修改,代码为:

static class MainThreadHandler extends Handler {

    MainThreadHandler() {
        super(Looper.getMainLooper());
    }

    void enqueue(Subscription subscription, Object event) {
        Message message = Message.obtain();
        //现在有两个对象需要传递,但Message只能传递单个对象,而Java没有元祖类型,所以需要自己创建对象或者放入数组中
        message.obj = PendingPost.obtain(subscription, event);
        
        if (!sendMessage(message)) {//发送失败:usually because the looper processing the message queue is exiting.
            throw new RuntimeException("Could not send handler message");
        }
    }

    @Override
    public void handleMessage(Message msg) {
        PendingPost pendingPost = (PendingPost) msg.obj;
        postEvent(pendingPost.subscription, pendingPost.event);
        pendingPost.recycle();//回收
    }
}
复制代码

总结

我们可以看出,1.0.1版本还是有些bug和不足的,后面我将分析2.x和3.x版本。