EventBus-源码分析

1,173 阅读9分钟
前言

EventBus是一个用于 Android 和 Java 的开源库,使用发布者/订阅者模式进行松散耦合,EventBus 只需几行代码即可实现与解耦类的集中通信——简化代码、消除依赖关系并加快应用程序开发。 它不仅可以很方便的在同线程中传递事件或者对象,还可以在不同线程中实现事件或对象的传递,用法比较简单,可以很好地完成一些在原生系统中的Intent,Handler等可以完成的工作,在Android开发过程中用途及其广泛。

下边是官方的 EventBus 原理图:

EventBus-Publish-Subscribe.png

EventBus的具体使用可以参考官网,这里不做具体的说明,本文主要从EventBus的使用入手,来具体分析EventBus的实现原理。

  • Subscribe注解
  • 事件订阅的注册
  • 发送事件
  • 取消注册
1.Subscribe注解

EventBus在要处理的事件订阅方法上需要加上@Subscribe标记,例如:

@Subscribe(threadMode = ThreadMode.MAIN,priority = 100,sticky = true)
public void testEvent(String msg){
  //do something
  ...
}

这个事件类型可以是Java中已有的类型,也可以是我们自定义的类型,下面我们看下@Subscribe注解:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    
   // 指定事件订阅方法的线程模式,即在那个线程执行事件订阅方法处理事件,默认为POSTING
    ThreadMode threadMode() default ThreadMode.POSTING;

   //是否为粘性事件,默认为false
    boolean sticky() default false;
  
   // priority 执行的优先级 数值越大优先级越高
    int priority() default 0;
}

因此在使用时,我们需要根据自己的需求指定threadMode、sticky、priority三个参数,下面我们看一下threadMode这个参数:

threadMode可以指定的参数如下:

public enum ThreadMode {
    /**
     * 同一个线程,在哪个线程发送事件,那么该方法就在哪个线程执行,避免线程切换
     */
    POSTING,
    
    /**
     * 无论在哪个线程发送事件,都在主线程中执行
     */
    MAIN,
   
    /**
     * 子线程:如果发布事件的线程是主线程,那么调用线程池中的子线程来执行订阅方法;否则直接执行;
     */
    BACKGROUND,
  
    /**
     * 异步线程:无论发布事件执行在主线程还是子线程,都利用一个异步线程来执行订阅方法。
     */
    ASYNC
}
2.事件订阅的注册

事件的注册方式如下:

EventBus.getDefault().register(this);

这里 EventBus.getDefault() 这里采用了单例去获取EventBus对象,保证了只存在一个EventBus对象:

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

在 new EventBus() 这个构造方法中就是初始化一些参数了,没什么可看的了

public EventBus() {
    this(DEFAULT_BUILDER);
}

EventBus(EventBusBuilder builder) {
    subscriptionsByEventType = new HashMap<>();
    typesBySubscriber = new HashMap<>();
    stickyEvents = new ConcurrentHashMap<>();
    mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
    backgroundPoster = new BackgroundPoster(this);
    asyncPoster = new AsyncPoster(this);
    indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
            builder.strictMethodVerification, builder.ignoreGeneratedIndex);
    logSubscriberExceptions = builder.logSubscriberExceptions;
    logNoSubscriberMessages = builder.logNoSubscriberMessages;
    sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
    sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
    throwSubscriberException = builder.throwSubscriberException;
    eventInheritance = builder.eventInheritance;
    executorService = builder.executorService;
}

有了EventBus对象,下面就是注册 register() 方法了:

public void register(Object subscriber) {
    // 首先获得class对象
    Class<?> subscriberClass = subscriber.getClass();
    // 通过 subscriberMethodFinder 来找到订阅者订阅了哪些事件.返回一个 SubscriberMethod 对象的 List, SubscriberMethod
    // 里包含了这个方法的 Method 对象,以及将来响应订阅是在哪个线程的 ThreadMode ,以及订阅的事件类型 eventType ,以及订阅的优
    // 先级 priority ,以及是否接收粘性 sticky 事件的 boolean 值,其实就是解析这个类上的所有 Subscriber 注解方法属性。
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            // 订阅
            subscribe(subscriber, subscriberMethod);
        }
    }
}

这里面的 findSubscriberMethods()、subscribe() 方法,我们都需要注意,下面我们分别来看下这两个方法:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    // 先从缓存里面读取,订阅者的 Class
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) {
        return subscriberMethods;
    }
    // ignoreGeneratedIndex属性表示是否忽略注解器生成的MyEventBusIndex。
    // ignoreGeneratedIndex的默认值为false,可以通过EventBusBuilder来设置它的值
    if (ignoreGeneratedIndex) {
        // 利用反射来获取订阅类中所有订阅方法信息
        subscriberMethods = findUsingReflection(subscriberClass);
    } else {
        // 从注解器生成的MyEventBusIndex类中获得订阅类的订阅方法信息
        subscriberMethods = findUsingInfo(subscriberClass);
    }
    if (subscriberMethods.isEmpty()) {
        throw new EventBusException("Subscriber " + subscriberClass
                + " and its super classes have no public methods with the @Subscribe annotation");
    } else {
        METHOD_CACHE.put(subscriberClass, subscriberMethods);
        return subscriberMethods;
    }
}
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    // FindState 涉及到 享元设计模式
    FindState findState = prepareFindState();

    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        findState.subscriberInfo = getSubscriberInfo(findState);
        if (findState.subscriberInfo != null) {
            SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
            for (SubscriberMethod subscriberMethod : array) {
                if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                    findState.subscriberMethods.add(subscriberMethod);
                }
            }
        } else {
            findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    // 释放 findState 享元模式
    return getMethodsAndRelease(findState);
}
private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        // This is faster than getMethods, especially when subscribers are fat classes like Activities
        // 通过反射来获取订阅类的所有方法
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
        methods = findState.clazz.getMethods();
        findState.skipSuperClasses = true;
    }
    // for 循环所有方法
    for (Method method : methods) {
        // 获取方法访问修饰符
        int modifiers = method.getModifiers();
        //  找到所有声明为 public 的方法
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            Class<?>[] parameterTypes = method.getParameterTypes();// 获取参数的的 Class
            if (parameterTypes.length == 1) {// 只允许包含一个参数
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                if (subscribeAnnotation != null) {
                    // 获取事件的 Class ,也就是方法参数的 Class
                    Class<?> eventType = parameterTypes[0];
                    // 检测添加
                    if (findState.checkAdd(method, eventType)) {
                        // 获取 ThreadMode
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                        // 往集合里面添加 SubscriberMethod ,解析方法注解所有的属性
                        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 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");
        }
    }
}

从上面可以看出 findSubscriberMethods()方法,会通过对象类的class反射获取所有的方法,通过遍历这些方法 通过判断是否为Public修饰符、是否只有一个参数、是否为Subscribe注解修饰,获取到修要处理的方法,将这些方法的参数封装为一个SubscriberMethod对象,一个Subscribe注解方法对应一个SubscriberMethod对象,这些参数包括 method、eventType、threadMode、priority,sticky,该方法执行完毕之后没,就获得一个类型为SubscriberMethod的List集合。

未命名2.png

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    // 获取方法参数的 class
    Class<?> eventType = subscriberMethod.eventType;
    // 创建一个 Subscription
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    // 获取订阅了此事件类的所有订阅者信息列表
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions == null) {
        // 线程安全的 ArrayList
        subscriptions = new CopyOnWriteArrayList<>();
        // 添加
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
        // 是否包含,如果包含再次添加抛异常
        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++) {
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }
    // 通过 subscriber 获取  List<Class<?>>
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    // 将此事件类加入 订阅者事件类列表中
    subscribedEvents.add(eventType);

    // 处理粘性事件
    if (subscriberMethod.sticky) {
        if (eventInheritance) {
            Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
            for (Map.Entry<Class<?>, Object> entry : entries) {
                Class<?> candidateEventType = entry.getKey();
                if (eventType.isAssignableFrom(candidateEventType)) {
                    Object stickyEvent = entry.getValue();
                    checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                }
            }
        } else {
            Object stickyEvent = stickyEvents.get(eventType);
            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
        }
    }
}

从上面我们可以看出subscribe()方法把 subscriber , SubscriberMethod 分别存好,将数据封装成了两个Map集合进行保存,下面我们看下这两个map集合,

    /** 
     * key 是 Event 参数的类
     * value 存放的是 Subscription 的集合列表
     *  Subscription 包含两个属性,一个是 subscriber 订阅者(反射执行对象),一个是 SubscriberMethod 注解方法的所有属性参数值
     */
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
  
 
    /**
     * key 是所有的订阅者
     * value 是所有订阅者里面方法的参数的 class,eventType
     */
    private final Map<Object, List<Class<?>>> typesBySubscriber;

未命名.png

3.发送事件

发送事件方式如下:

EventBus.getDefault().post("Message");
public void post(Object event) {
    // currentPostingThreadState 是一个 ThreadLocal,
    // 他的特点是获取当前线程一份独有的变量数据,不受其他线程影响。
    PostingThreadState postingState = currentPostingThreadState.get();
    // postingState 就是获取到的线程独有的变量数据
    List<Object> eventQueue = postingState.eventQueue;
    // 把 post 的事件添加到事件队列
    eventQueue.add(event);
    // 如果没有处在事件发布状态,那么开始发送事件并一直保持发布状态
    if (!postingState.isPosting) {
        // 是否是主线程
        postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
        // isPosting = true
        postingState.isPosting = 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;
        }
    }
}
  1. 根据 currentPostingThreadState 获取当前线程状态 PostingThreadState 。currentPostingThreadState 其实就是一个 ThreadLocal 类的对象,不同的线程根据自己独有的索引值可以得到相应属于自己的 postingState 数据。

  2. 然后把事件 event 加入到 eventQueue 集合中。

  3. 循环遍历 eventQueue ,取出事件发送事件。发送单个事件是调用 postSingleEvent(Object event, PostingThreadState postingState) 方法。

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    // 得到事件的Class
    Class<?> eventClass = event.getClass();
    // 是否找到订阅者
    boolean subscriptionFound = false;
    // 如果支持事件继承,默认为支持
    if (eventInheritance) {
        // 查找 eventClass 的所有父类和接口
        List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
        int countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
            Class<?> clazz = eventTypes.get(h);
            // 依次向 eventClass 的父类或接口的订阅方法发送事件
            // 只要有一个事件发送成功,返回 true ,那么 subscriptionFound 就为 true
            subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
        }
    } else {
        // 发送事件
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    }
    // 如果没有订阅者
    if (!subscriptionFound) {
        if (logNoSubscriberMessages) {
            Log.d(TAG, "No subscribers registered for event " + eventClass);
        }
        if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) {
            post(new NoSubscriberEvent(this, event));
        }
    }
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
    CopyOnWriteArrayList<Subscription> subscriptions;
    synchronized (this) {
        // 得到Subscription 列表
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    if (subscriptions != null && !subscriptions.isEmpty()) {
        // 遍历 subscriptions
        for (Subscription subscription : subscriptions) {
            //
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted = false;
            try {
                // 发送事件
                postToSubscription(subscription, event, postingState.isMainThread);
                // 是否被取消了
                aborted = postingState.canceled;
            } finally {
                postingState.event = null;
                postingState.subscription = null;
                postingState.canceled = false;
            }
            // 如果被取消,则跳出循环
            if (aborted) {
                break;
            }
        }
        return true;
    }
    return false;
}
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    // 根据不同的线程模式执行对应
    switch (subscription.subscriberMethod.threadMode) {
        // 和发送事件处于同一个线程
        case POSTING:
            invokeSubscriber(subscription, event);
            break;
        // 主线程
        case MAIN:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        // 子线程
        case BACKGROUND:
            if (isMainThread) {
                backgroundPoster.enqueue(subscription, event);
            } else {
                invokeSubscriber(subscription, event);
            }
            break;
        // 和发送事件处于不同的线程
        case ASYNC:
            asyncPoster.enqueue(subscription, event);
            break;
        default:
            throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
    }
}

这里可以看到根据设置的threadMode 去选择不同的方式去处理事件,处理的方式有主要两种:

1.invokeSubscriber(subscription, event);

这种是通过反射来执行订阅事件的方法,这样发送出去的事件就被订阅者接收并做相应处理了

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

2.xxxPoster.enqueue(subscription, event)

这种是将对象加入队列(底层其实就是一个List< PendingPost >集合),然后通过Hander进行进一步处理,这里以mainThreadPoster.enqueue(subscription, event)为例,进行分析:

final class HandlerPoster extends Handler {

    private final PendingPostQueue queue;
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    ......

    void enqueue(Subscription subscription, Object event) {
         //PendingPost是用subscription和event封装一个PendingPost对象
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            //入列
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
            // 发送开始处理事件的消息,handleMessage()方法将被执行,完成从子线程到主线程的切换,确保在主线程执行
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                //出列
                PendingPost pendingPost = queue.poll(); 
                ......
                //去执行该事件
                eventBus.invokeSubscriber(pendingPost);
                ......
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}

从上面可以看出,HandlerPoster的enqueue方法就是将subscription、event封装成一个PendingPost对象,加入队列,然后通过Handler切换到主线程,确保订阅事件在主线程执行,在handleMessage()中将PendingPost循环出队列,交给invokeSubscriber()方法执行。

void invokeSubscriber(PendingPost pendingPost) {
    Object event = pendingPost.event;
    Subscription subscription = pendingPost.subscription;
    //释放PendingPost引用资源
    PendingPost.releasePendingPost(pendingPost);
    if (subscription.active) {
        //和第一种方式一样,通过反射去执行订阅事件
        invokeSubscriber(subscription, event);
    }
}
3.取消注册

取消注册的方式如下:

EventBus.getDefault().unregister(this);
public synchronized void unregister(Object subscriber) {
    // 获取订阅对象的所有订阅事件类列表
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        for (Class<?> eventType : subscribedTypes) {
            // 将订阅者的订阅信息移除
            unsubscribeByEventType(subscriber, eventType);
        }
        // 将订阅者从列表中移除
        typesBySubscriber.remove(subscriber);
    } else {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}

这里unregister()没有做任何处理,只是获取取消注册的对象的的订阅事件类列表,循环遍历,下面继续看unsubscribeByEventType()方法。

private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
    // 获取事件类的所有订阅信息列表,将订阅信息从订阅信息集合中移除,同时将订阅信息中的active属性置为FALSE
    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) {
                // 将订阅信息激活状态置为FALSE
                subscription.active = false;
                // 将订阅信息从集合中移除
                subscriptions.remove(i);
                i--;
                size--;
            }
        }
    }
}

所以在unregister()方法中,释放了typesBySubscribersubscriptionsByEventType中缓存的资源。