EventBus原理篇(1)

沒看過EventBus用法的童鞋移駕到EventBus基礎(chǔ)用法,現(xiàn)在來探索EventBus的源碼。
EventBus構(gòu)造方法
?當(dāng)要使用EventBus時,首先會調(diào)用EventBus.getDefault()來獲取EventBus實例?,F(xiàn)在查看getDefuelt方法做了什么,如下:

 /** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

?很明顯這是一個單例模式,采用了雙重檢查模式(DCL)。接下來查看EventBus的構(gòu)造方法做了什么:

/**
     * Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
     * central bus, consider {@link #getDefault()}.
     */
 public EventBus() {
        this(DEFAULT_BUILDER);
    }

?這里DEFAULT_BUILDER是默認的EventBusBuilder,用來構(gòu)造EventBus:

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

?this調(diào)用了EventBus的另外一個構(gòu)造方法,如下:

EventBus(EventBusBuilder builder) {
        logger = builder.getLogger();
        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);
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        eventInheritance = builder.eventInheritance;
        executorService = builder.executorService;
    }

?可以通過構(gòu)造一個EventBusBuilder來對EventBus進行配置,這里采用了建造者模式。
訂閱者注冊
?獲取EventBus后,便可以將訂閱者注冊到EventBus中。下面來看下register方法:

 /**
     * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
     * are no longer interested in receiving events.
     * <p/>
     * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
     * The {@link Subscribe} annotation also allows configuration like {@link
     * ThreadMode} and priority.
     */
    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//1
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);//2
            }
        }
    }

(1)查找訂閱者的訂閱方法
?上面代碼注釋1處的findSubscriberMethods方法找出一個SubscriberMethod的集合,也就是傳進來的訂閱者的所有方法,接下來遍歷訂閱者的訂閱方法來完成訂閱者的注冊操作??梢钥闯鰎egsiter方法做了兩件事:一件事是查找訂閱者的訂閱方法,另一種是訂閱者的注冊。在SubscriberMethod類中,只要用來保存訂閱者方法的Methed對象、線程模式、事件類型、優(yōu)先級、是否是黏性事件等屬性。下面就來查看findSubscriberMethods方法,如下:


    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);//1
        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.put(subscriberClass, subscriberMethods);//2
            return subscriberMethods;
        }
    }

?上面代碼注釋1處從緩存中查找是否有訂閱方法的集合,如果找到了就立馬返回。如果緩存中沒有,則根據(jù)ignoreGeneratedIndex屬性中的值來選擇采用何種方法來查找訂閱方法的集合。ignoreGeneratedIndex屬性表示是否忽略注解器生成的MyEventBusIndex。如何生成MyEventBusIndex類以及它的使用,可以參考官方分檔,這里不再講解了。ignoreGeneratedIndex的默認值是false,可以通過EventBusBuilder來設(shè)置它的值。在注釋2處找到訂閱方法的集合后,放入緩存,以免下次繼續(xù)查找。我們在項目中經(jīng)常通過EventBus單例模式來獲取的EventBus對象,也就ignoreGeneratedIndex為false的情況,這種情況調(diào)用了注釋3處的findUsingInfo方法:

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass){
      FindState findState = prepareFindState();
      findState.initForSubscriber(subscriberClass);
      whild(findState.clazz !=null){
          findState.subsciberInfo = getSubscriberInfo(findState);//1
          if(findState.subscriberInfo!=null){
              SubscriberMethed[] array = findState.subscriberInfo.getSubscriberMethods();//2
            for(SubscriberMethed subscriberMethod : array){
                 if(findState.checkAdd(subscriberMethod.method,subscriberMethod.eventType)){
                    findState.subscriberMethods.add(subscriberMethod);
              }
            }
          }else {
              findUsingReflectionInSingleClass(findState);
          }
          findState.moveToSuperclass();
      }
      return getMethodsAndRelease(findState);
    }

?上面代碼注釋1處通過getSubscriberInfo方法來獲取訂閱者信息。在我們開始查找訂閱方法的時候并沒有忽略注釋器為我們生成的索引MyEventBusIndex。如果我們通過EventBusBuilder配置了MyEventBusIndex,便會獲取subscriberInfo。注釋2處調(diào)用subscriberInfo的getSubscriberMethods方法便可以得到訂閱方法相關(guān)的信息。如果沒有配置MyEventBusIndex,后再通過getMethodsAndRelease方法對findState做回收處理并返回訂閱方法的List集合。默認情況下是沒有配置MyEventBusIndex的,因此現(xiàn)在查看下findUsing-ReflectionInSingleClass方法的執(zhí)行過程,所示:

private void findUsingRelfectionInSingleClass(FindState findState){
    Method[] methods;
    try{
        methods = findState.clazz.getDeclaredMethods();//1
    }catch{
        methods = findState.clazz.getMethods();
        findState..skipSupreClasses = true;
    }
    for (Method method : methods) {
      int modifiers = method.getModifiers();
      if((modidiers & Modifier.PUBLIC)!=0&&(modifiers & MODIFIERS_IGNORE)==0){
          Class<?>[] =  parameterTypes = method.getParameterTypes();
          if(parameterTypes.length == 1 ){
            Subscribe subscribeAnntation = method.getAnntaotion(Subscribe.class);
              if(subscribeAnnotation != null){
                 Class<?> eventType = parameterTypes[0];
                if(findState.checkAdd(method,eventType)){
                  ThreadMode = threadMode = subscribeAnnotation.threadMode();
                    findState.subscriberMethods.add(new SuberciberMethod
(method,eventType,threadMode,subscribeAnntation.priority,subcribeAnnotation.sticky()));
                }
              }
          }
      }
    }
}

?上面代碼注釋1處通過反射來獲取訂閱者中所有的方法,并根據(jù)方法的類型、參數(shù)和注解來找到訂閱方法。找到訂閱方法后將訂閱的相關(guān)信息保存到findState中。
&#8195;(2)訂閱者的注冊過程
&#8195;在查找完訂閱方法以后便開始對所有的訂閱方法進行注冊。我們再回到register方法中,在哪里的注釋2處調(diào)用subscribe方法來對訂閱方法進行注冊,所示:

private void subscribe(Object subscriber,SubscriberMethod subscricberMethod){
    Class<?> eventType = subscriberMethod.eventType;
    Subscription newSubscription = new Subscription(subscriber,SubscriberMethod);//1
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionByEventType.get(eventType);//2
    if(subscriptions == null){
      subscriptions  = new CopyOnWriteArrayList<>();
      subscriptionsByEventType.put(eventType,subscriptions);
    }else{
     //判斷訂閱者是否已經(jīng)被注冊
        if(subscriptions .comtains(newSubscription)){
            throw new EventBusException("Subcriber"+subscriber.getClass() + "already registered to event "+eventType);
        }
    }
     int size  = subscriptions.size();
      for (int i = 0;  i = size; i++){
        if(i ==size||subscriberMethod.priority > subscriprions.get(i).subscriberMethod.priority){
        subscriptions.add(i,newSubscription );//3
          break;
        }
      }
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);//4
    if(subscribedEvents == null){
      subscribedEvents = new ArrayList<>();
      typesBySubscriber.put(subscriber,subecribedEvents);
    }
   ; subscribedEvents.add(eventType);
    if(subscriberMethod.sticky){
        if(eventInheritance){
            //粘性事件的處理
            Set<Map.Entry<Class<?>>,Object> entries = stickyEvents.entrySet();
            for(Set<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);
        }
    }
}

?首先,上面代碼注釋1處根據(jù)subscriber(訂閱者)和subscriberMethod(訂閱方法)創(chuàng)建一個Subscription(訂閱對象)。注釋2處根據(jù)eventType(事件類型)獲取Subscriptions(訂閱對象集合)。如果Subscriptions為null則重新創(chuàng)建,并將Subscriptions根據(jù)eventType保存在subscriptionsByEventType(Map集合)。注釋3處按照訂閱方法的優(yōu)先級插入到訂閱對象集合中,完成訂閱方法的注冊。注釋4處通過subscriber獲取subsrcibedEvents(事件類型集合)。如果subscribedEvents為null則重新創(chuàng)建,并將eventType添加到subscribedEvents中,并根據(jù)subscriber將subscribedEvents存儲在typesBySubscriber(Map集合)。如果是粘性事件,則從stickyEvents事件保存隊列中取出該事件類型的事件發(fā)送給當(dāng)前訂閱者??偨Y(jié)下,subscribe發(fā)法主要就是做了兩件事:一件事是將Subscriptions根據(jù)eventType封裝到subscriptionsByEventType中,將subscribedEvents根據(jù)subscriber封裝到typesBySubscriber中;第二件事就是對粘性事件的處理。
喜歡的童鞋,動動手指點贊,收藏,轉(zhuǎn)發(fā),評論。增加博主更新動力!??!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容