1. 注册及查找事件
1.1 EventBus初始化
- getDefault: 通过单例模式获取实例,同时里面采用Builder模式构造部分初始化参数,方便定制部分配置信息
//Builder模式,在EventBusBuilder里面完成一些默认的初始化操作 private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder(); public static EventBus getDefault() { //通过DCL单例模式创建EventBus实例 } public EventBus() { this(DEFAULT_BUILDER); } EventBus(EventBusBuilder builder) { //通过EventBusBuilder完成的初始化构造 }
1.2 EventBus注册
-
register:根据订阅者类信息,查询对应的订阅方法信息,遍历注册订阅方法
public void register(Object subscriber) { //根据订阅者的类名信息查询订阅方法 Class<?> subscriberClass = subscriber.getClass(); List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { //遍历并注册这些订阅方法 for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
-
SubscriberMethod:封装了订阅方法的基本类型信息,即@Subscribe中所注解的内容
public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) { this.method = method; this.threadMode = threadMode; this.eventType = eventType; this.priority = priority; this.sticky = sticky; }
1.3 查询订阅者所有的订阅方法
-
findSubscriberMethods: 查询订阅者所有的订阅方法,三种查询方式:缓存,通过注解器索引,反射
//METHOD_CACHE缓存了订阅及其所有订阅方法 private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>(); List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { //首先查找缓存 List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } //ignoreGeneratedIndex默认为false,表示是否忽略注解生成器 if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass);//通过反射获取 } else { subscriberMethods = findUsingInfo(subscriberClass);//通过注解的方式 } if (subscriberMethods.isEmpty()) {//如果当前订阅者没有声明订阅方法,则抛出异常 } else { //将订阅者及订阅方法存入缓存中 METHOD_CACHE.put(subscriberClass, subscriberMethods); ... } }
1.3.1 通过注解索引的方式获取订阅者的订阅方法
-
findUsingInfo:获取订阅者信息,并且对其父类进行向上查询,最后将所有订阅方法信息封装到subscriberMethods列表中返回
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { FindState findState = prepareFindState();//通过对象池的方式复用FindState 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.clazz改为subscriberClass的父类Class,再进行遍历 findState.moveToSuperclass(); } return getMethodsAndRelease(findState);//回收FindState对象到对象池中,并返回subscriberMethods列表 } ... //实现对象池 private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];// POOL_SIZE = 4; private FindState prepareFindState() { synchronized (FIND_STATE_POOL) { for (int i = 0; i < POOL_SIZE; i++) { FindState state = FIND_STATE_POOL[i]; if (state != null) { FIND_STATE_POOL[i] = null; return state; } } } return new FindState(); }
-
getSubscriberInfo:遍历订阅者索引,返回查找的订阅者的信息
private SubscriberInfo getSubscriberInfo(FindState findState) { //上面已经有一次判断,所以这个条件不会进入 if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) { SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo(); if (findState.clazz == superclassInfo.getSubscriberClass()) { return superclassInfo; } } //遍历订阅者索引,查找订阅者的信息 if (subscriberInfoIndexes != null) { for (SubscriberInfoIndex index : subscriberInfoIndexes) { SubscriberInfo info = index.getSubscriberInfo(findState.clazz); if (info != null) { return info; } } } return null; }
-
FindState 主要用来辅助存储订阅者信息
static class FindState { final List<SubscriberMethod> subscriberMethods = new ArrayList<>(); final Map<Class, Object> anyMethodByEventType = new HashMap<>(); final Map<String, Class> subscriberClassByMethodKey = new HashMap<>(); final StringBuilder methodKeyBuilder = new StringBuilder(128); ... void moveToSuperclass() { ... }// 修改findState.clazz为subscriberClass的父类Class }
1.3.2 通过反射获取订阅者的订阅方法
-
findUsingReflection
//FindState主要用来辅助存储订阅者信息 private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) { FindState findState = prepareFindState();//通过对象池的方式复用FindState findState.initForSubscriber(subscriberClass);//初始化参数并将订阅者类信息导入 while (findState.clazz != null) { findUsingReflectionInSingleClass(findState);//通过反射查询订阅者的订阅方法 // 将findState.clazz改为subscriberClass的父类Class,再进行遍历 findState.moveToSuperclass(); } return getMethodsAndRelease(findState);//回收FindState对象到对象池中,并返回subscriberMethods列表 }
-
findUsingReflectionInSingleClass:通过反射查询订阅者的订阅方法
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 methods = findState.clazz.getMethods(); findState.skipSuperClasses = true; } for (Method method : methods) { int modifiers = method.getModifiers(); //校验方法修饰属性,是否PUBLIC及MODIFIERS_IGNORE // MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; 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(); //将订阅方法及方法的注解信息封装到列表中 findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { //抛出异常 } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { //抛出异常 } } }
1.4 注册订阅方法:
-
subscribe:将订阅者和订阅方法封装成对象,并将相同事件类型的封装对象根据事件优先级封装到CopyOnWriteArrayList集合中,再将事件类型和CopyOnWriteArrayList封装到map集合中
Map<Object, List<Class<?>>> typesBySubscriber; Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; Map<Class<?>, Object> stickyEvents = new ConcurrentHashMap<>(); private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class<?> eventType = subscriberMethod.eventType; //将订阅者和订阅方法封装成对象 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); //查询出同样事件类型的所有Subscription对象 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); //通过CopyOnWriteArrayList对订阅事件对象按事件类型,按照优先级进行存储(同优先级则插入末尾),并校验是否多次注册(已注册抛出异常) if (subscriptions == null) { 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; } } //将订阅者对象和订阅事件存储对应存储到map集合中 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); } } }
2. 发布通知消息
-
post:通过在ThreadLocal中封装一个事件队列,去添加和执行相应的事件
public void post(Object event) { //在ThreadLocal中封装一个线程状态信息,里面包含一个事件队列 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); } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } } private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } };
-
postSingleEvent
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { 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); } ... //找不到事件时异常处理 NoSubscriberEvent } private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { //获取对应的订阅者 subscriptions = subscriptionsByEventType.get(eventClass); } ... for (Subscription subscription : subscriptions) { postingState.event = event; postingState.subscription = subscription; boolean aborted = false; try {//通知订阅者 postToSubscription(subscription, event, postingState.isMainThread); aborted = postingState.canceled; } finally { ...//重置postingState属性 } if (aborted)break; } ... }
-
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); } else { //如果不是主线程,则加入到主线程执行队列中执行,mainThreadPoster继承自Handler 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; ... } } ... void invokeSubscriber(Subscription subscription, Object event) { ... subscription.subscriberMethod.method.invoke(subscription.subscriber, event); }
3. 发布粘性通知
-
postSticky: 粘性事件会通过单独的stickyEvents集合进行存储,同时会在事件订阅的时候进行check post,继而实现粘性这一效果
public void postSticky(Object event) { synchronized (stickyEvents) { stickyEvents.put(event.getClass(), event); //添加到粘性事件列表,在上述注册订阅方法时,会通过列表去通知信息 } // Should be posted after it is putted, in case the subscriber wants to remove immediately post(event);//发布通知,当前已经订阅的订阅者可以收到 } ... private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { ... 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); } } }