1. 注冊及查找事件
1.1 EventBus初始化
- getDefault: 通過單例模式獲取實例愈污,同時里面采用Builder模式構造部分初始化參數(shù)张遭,方便定制部分配置信息
//Builder模式,在EventBusBuilder里面完成一些默認的初始化操作 private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder(); public static EventBus getDefault() { //通過DCL單例模式創(chuàng)建EventBus實例 } public EventBus() { this(DEFAULT_BUILDER); } EventBus(EventBusBuilder builder) { //通過EventBusBuilder完成的初始化構造 }
1.2 EventBus注冊
-
register:根據(jù)訂閱者類信息畔裕,查詢對應的訂閱方法信息法精,遍歷注冊訂閱方法
public void register(Object subscriber) { //根據(jù)訂閱者的類名信息查詢訂閱方法 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);//初始化參數(shù)并將訂閱者類信息導入 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列表 } ... //實現(xiàn)對象池 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) { //上面已經(jīng)有一次判斷蘑秽,所以這個條件不會進入 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);//初始化參數(shù)并將訂閱者類信息導入 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();//校驗方法參數(shù) 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:將訂閱者和訂閱方法封裝成對象靴跛,并將相同事件類型的封裝對象根據(jù)事件優(yōu)先級封裝到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對訂閱事件對象按事件類型,按照優(yōu)先級進行存儲(同優(yōu)先級則插入末尾),并校驗是否多次注冊(已注冊拋出異常) 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) { // 迭代所有事件可能會導致很多粘性事件的效率低下,因此應該更改數(shù)據(jù)結構以允許更有效的查找 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. 發(fā)布通知消息
-
post:通過在ThreadLocal中封裝一個事件隊列梢睛,去添加和執(zhí)行相應的事件
public void post(Object event) { //在ThreadLocal中封裝一個線程狀態(tài)信息肥印,里面包含一個事件隊列 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()) { //遍歷發(fā)送當前事件隊列 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); //發(fā)送該事件 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:通知訂閱者识椰,對于不同線程發(fā)布消息會調用相應的線程事件隊列去執(zhí)行
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 { //如果不是主線程,則加入到主線程執(zhí)行隊列中執(zhí)行深碱,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) { //如果不是后臺線程腹鹉,則加入到后臺線程行隊列中執(zhí)行 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. 發(fā)布粘性通知
-
postSticky: 粘性事件會通過單獨的stickyEvents集合進行存儲,同時會在事件訂閱的時候進行check post敷硅,繼而實現(xiàn)粘性這一效果
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);//發(fā)布通知绞蹦,當前已經(jīng)訂閱的訂閱者可以收到 } ... private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { ... if (subscriberMethod.sticky) {//處理粘性事件 if (eventInheritance) { // 迭代所有事件可能會導致很多粘性事件的效率低下力奋,因此應該更改數(shù)據(jù)結構以允許更有效的查找 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); } } }