EventBus源码

342 阅读8分钟

1. EventBus用法

// EventBus的注册
 EventBus.getDefault().register(this);
 
// EventBus的解除注册
EventBus.getDefault().unregister(this);

// 发送事件
EventBus.getDefault().post(new Object());

// 接收事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void onOtherDisplay(Object obj) {

    }

2. EventBus实例化

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

    EventBus(EventBusBuilder builder) {
      ......
      
        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);
        
        
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
    ......
        executorService = builder.executorService;
    }

  • 采用双重校验锁的单例模式来获取EventBus的实例
  • **subscriptionsByEventType:**HashMap<事件类型,Subscription集合(注册类与订阅方法)>
  • **typesBySubscriber:**HashMap<存储key的注册类,事件类型集合的HashMap>,判断某个对象是否注册过,防止重复注册
  • **mainThreadPoster:**将线程模型为MAIN和Main_ordere的事件加入队列
  • **backgroundPoster:**将线程模型为background的事件加入到队列
  • **asyncPoster:**将线程模型为ASYNC的事件加入到队列

3. EventBus的注册

  • 从缓存中查找该注册类的订阅方法,缓存中有,直接返回,缓存中无,查找所有订阅方法,放入缓存中
  • 通过反射获取注册类中的所有方法,循环遍历这些方法,获取方法上的注解,获取方法的第一个参数为事件类型、线程模式、将方法、事件模型、线程模型、优先级、是否是粘性时间封装到SubscriberMethod对象,然后添加到FindState类中subscriberMethods中
  • 将注册类与订阅方法封装到Subscription中, 按照事件的优先级排序,subscriptions,这个后续会解除注册
  • subscriptionByEventType: 获取事件类型eventType,通过eventType查找subscriptionByEventType查找是否已有SubScrition集合,没有就创建加入subscriptionByEventType
  • typesBySubscriber : 一个存储 key 为注册类(对应使用示例中的 EventBusFirstActivity),value 为事件类型集合的 HashMap
  • 如果是粘性事件是,从stickEvents中取出,进行处理,根据线程模式判断是否需要切换线程,不需要则直接通过反射调用订阅方法;需要则通过 Handler 或线程池切换到指定线程再执行
    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); // 见【1】
        synchronized (this) {
          // 见【2】
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
【1】findSubscriberMethods()
  private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
    private final boolean ignoreGeneratedIndex;
    
   List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
     // 从METHOD_CACHE中查找是否已经缓存了该注册类上的订阅方法
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
          // 查找所有的订阅方法
            subscriberMethods = findUsingInfo(subscriberClass);// 见【3】
        } 
        if (subscriberMethods.isEmpty()) {
            throw new EventBusException("Subscriber " + subscriberClass
                    + " and its super classes have no public methods with the @Subscribe annotation");
        } else {
          // 如果查找所有的订阅方法缓存到METHOD_CACHE集合中
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

总结:

    1. 从缓存中查找该注册类的订阅方法,缓存中有,直接返回
    1. 缓存中无,查找所有订阅方法,放入缓存中
【3】findUsingInfo()
    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);// 见【5】
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

【5】findUsingReflectionInSingleClass()

    private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
             // 反射获取注册类中所有的方法
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            // 反射获取注册类中的所有方法
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
        // 循环遍历所有的方法
        for (Method method : methods) {
            int modifiers = method.getModifiers();
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {
                // 获取方法上的注解
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {
                 // 获取方法上第一个参数,即事件类型
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                  // 获取线程模式    
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                  // 将方法、事件模型、线程模型、优先级、是否是粘性时间封装到SubscriberMethod对象,然后添加到FindState类中subscriberMethods中          
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                } 
     .........           
        }
    }

总结:

通过反射获取注册类中的所有方法,循环遍历这些方法,获取方法上的注解,获取方法的第一个参数为事件类型、线程模式、将方法、事件模型、线程模型、优先级、是否是粘性时间封装到SubscriberMethod对象,然后添加到FindState类中subscriberMethods中

【2】Subscribe()
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    // 获取事件类型
        Class<?> eventType = subscriberMethod.eventType;
    // 将注册类与订阅方法封装到Subscription中
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    // 通过eventType查找subscriptionByEventType查找是否已有SubScrition集合,没有就创建加入subscriptionByEventType    
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
          ........
        }
    // 根据订阅的类中的newSubscription中的优先级加入到subscriptions
        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;
            }
        }
   // 将typesBySubscriber 是一个存储 key 为注册类(对应使用示例中的 EventBusFirstActivity),value 为事件类型集合的 HashMap
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);
   // 后续粘性事件相关逻辑,如果是粘性事件,postToSubscription(newSubscription, stickyEvent, isMainThread())
        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);
            }
        }
    }

总结:

  • 将注册类与订阅方法封装到Subscription中
  • 按照事件的优先级排序,subscriptions
  • subscriptionByEventType: 获取事件类型eventType,通过eventType查找subscriptionByEventType查找是否已有SubScrition集合,没有就创建加入subscriptionByEventType
  • typesBySubscriber : 一个存储 key 为注册类(对应使用示例中的 EventBusFirstActivity),value 为事件类型集合的 HashMap
  • 如果是粘性事件是,从stickEvents中取出,进行处理

4. EventBus的解除注册

注册的时候使用subsciptionByEventType集合中保存了所有的订阅方法信息,使用typesBySubscriber集合保存了所有的事件类型。解除绑定的时候移除这两个集合中保存的内容

 public synchronized void unregister(Object subscriber) {
      // 根据注册类获取typesBySubscriber集合中保存的事件类型
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType); // 见【6】
            }
          // 移除 typeBySubcriber中保存的事件类型集合
            typesBySubscriber.remove(subscriber);
        } else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }
【6】unsubscribeByEventType(subscriber, eventType)
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
      // 根据事件类型获取subScriptionByEventType集合中保存的Subscription集合
        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;
                  // 从subscription集合中移除
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }
5. 发送事件post
  • 主要是从事件队列中取出一个事件进行发送,所有事件类型,包括当前事件、父类和接口中的事件,如果没有找到订阅者,发送NoSubscriberEvent()事件 从 subscriptionsByEventType 集合中取出所有订阅方法,然后根据线程模式判断是否需要切换线程,不需要则直接通过反射调用订阅方法;需要则通过 Handler 或线程池切换到指定线程再执行。
   private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };
   

public void post(Object event) {
  // currentPostingThreadState是一个ThreadLocal对象,里面保存了PostingThreadState对象,
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            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); // 见【7】
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }
【7】postSingleEvent()
  private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        // 是否找到订阅者
        boolean subscriptionFound = false;
        //(1)表示是否需要发送父类与接口中的事件
        if (eventInheritance) {
            //(2)查找所有事件类型,包括当前事件、父类和接口中的事件。
            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); // 见【8】
            }
        } else {
            // 根据事件类型只发送当前注册类的事件,忽略父类以及接口。
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                //(5)没有找到订阅者,发送一个 NoSubscriberEvent 事件
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

【8】postSingleEventForEventType()
  private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
          // 从subscriptionsByEventType集合中取出之前注册的时候保存的SubScription集合,然后遍历集合拿到SubScription
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                try {
                    postToSubscription(subscription, event, postingState.isMainThread); // 见【9】
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }


【9】postToSubscription()
    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); // 见【10】
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(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);
        }
    }

根据不同线程模型来决定在哪个线程执行订阅方法

【10】invokeSubscriber()
 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);
        }
    }

直接通过反射调用

Main

如果线程模式是 MAIN,那么在主线程发送事件,则在主线程执行订阅方法;否则先将事件加入到队列中,然后通过 Handler 切换到主线程再执行invokeSubscriber()方法

public class HandlerPoster extends Handler implements Poster {

    private final PendingPostQueue queue;
    
    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    @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) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                eventBus.invokeSubscriber(pendingPost);
                long timeInMethod = SystemClock.uptimeMillis() - started;
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}

MAIN_ORDERED

如果线程模式是 MAIN_ORDERED,那么无论在哪个线程发送事件,都会先将事件加入到队列中,然后通过 Handler 切换到主线程再执行

BACKGROUND

subscription 和 event 封装成一个 PendingPost 对象,然后加入到队列中。不同的是这里不是使用 Handler 发送消息,而是通过线程池去执行。所以,如果线程模式是 BACKGROUND,那么在子线程发送事件,则在子线程执行订阅方法,否则先将事件加入到队列中,然后通过线程池去执行

final class BackgroundPoster implements Runnable, Poster {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

    private volatile boolean executorRunning;

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

    public void enqueue(Subscription subscription, Object event) {
        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 interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

}

ASYNC

无论在哪个线程发送事件,都会先将事件加入到队列中,然后通过线程池去执行。

class AsyncPoster implements Runnable, Poster {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

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

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        queue.enqueue(pendingPost);
        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);
    }

}