EventBus 使用以及源碼淺析

EventBus用法及解析

EventBus介紹:

!
1.png
  • EventBus主要是用來組件之間進(jìn)行信息傳遞的宝鼓,相對(duì)于接口回調(diào)的方式的話澜薄,EventBus是可以解耦兩個(gè)組件的赶诊,而接口回調(diào)潮模,需要傳遞一個(gè)接口對(duì)象到另一個(gè)組件罢绽,耦合度比較高宠互,而且如果在界面銷毀時(shí)處理不當(dāng),還有可能造成內(nèi)存泄漏椭坚,EventBus的另一個(gè)優(yōu)點(diǎn)就是使用非常方便予跌,API調(diào)用非常簡(jiǎn)單。

EventBus使用

  • 添加依賴

      compile 'org.greenrobot:eventbus:3.1.1'
    
  • 在需要發(fā)送消息的地方善茎,添加如下代碼

       EventBus.getDefault().post(messageEvent);
    
  • 在需要接收到事件的組件中需要做如下處理

    • 注冊(cè)EventBus券册;
        EventBus.getDefault().register(this); 
* 定義一個(gè)接收事件的方法;

         @Subscribe(threadMode = ThreadMode.ASYNC, sticky = true)
         public void onMessageEvent(MessageObject object) {
                //執(zhí)行接收到事件的操作
         }
    
         這里有幾個(gè)點(diǎn)需要注意:
            1. 必須要帶有@Subscibe 并且方法的參數(shù)只能為1個(gè) 垂涯,修飾的關(guān)鍵字只能為public
            2. 可以指定線程烁焙,不指定默認(rèn)為發(fā)出事件的那個(gè)線程;
                1.ThreadMode.ASYNC
                2.ThreadMode.POSTING
                3.ThreadMode.MAIN
                4.ThreadMode.BackGround
            3. 可以指定當(dāng)前接收的事件是否為粘性事件耕赘,正常事件發(fā)送時(shí)骄蝇,組件必須已經(jīng)注冊(cè),不然無法接收到事件鞠苟,而粘性事件的話乞榨,如果發(fā)送時(shí)組件沒有注冊(cè),也可以接收到事件(發(fā)送時(shí)必須通過PostSticky()而不是post 当娱, 會(huì)將該事件添加到Sticky事件集合)
* 在組件銷毀時(shí)吃既,取消注冊(cè);

         EventBus.getDefault().unregister(this);

EventBus源碼解析

從上面的EventBus使用可以看出EventBus使用非常簡(jiǎn)單跨细,那么EventBus底層究竟是怎么做的鹦倚,我們可以一起學(xué)習(xí)下

  • EventBus注冊(cè)過程
    EventBus首先需要調(diào)用getDefault()方法,那么我們 getDefault方法中究竟做了什么

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

    可以看出只是通過單例模式構(gòu)造了一個(gè)EventBus對(duì)象冀惭,調(diào)用了EventBus()的構(gòu)造方法

    public EventBus() {
        this(DEFAULT_BUILDER);
    }

    EventBus(EventBusBuilder builder) {
        logger = builder.getLogger(); //是否打印log
        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)造方法中需要傳入一個(gè)EventBusBuilder對(duì)象震叙,我們?cè)趃etDefault()時(shí)傳遞了一個(gè)DEFAULT_BUILDER

    private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    boolean logSubscriberExceptions = true;
    boolean logNoSubscriberMessages = true;
    boolean sendSubscriberExceptionEvent = true;
    boolean sendNoSubscriberEvent = true;
    boolean throwSubscriberException;
    boolean eventInheritance = true;
    boolean ignoreGeneratedIndex;   // 查找方法策略
    boolean strictMethodVerification;
    ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
    List<Class<?>> skipMethodVerificationForClasses;
    List<SubscriberInfoIndex> subscriberInfoIndexes;
    Logger logger;
    MainThreadSupport mainThreadSupport;

    EventBusBuilder() {
    }
而DEFAULT_BUILDER只是一個(gè)默認(rèn)值得Builder對(duì)象 , 有的變量在后面的分析中會(huì)用到散休,也就是說EventBus在getDefault()時(shí)媒楼,只是通過雙重判斷構(gòu)造了一個(gè)EventBus單利對(duì)象,傳入一個(gè)具有默認(rèn)值得EventBusBuilder對(duì)象戚丸,接下來看register這個(gè)方法

    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }   
    
在register時(shí)划址,我們傳遞了當(dāng)前類,然后通過findSubscriberMethods(subscriberClass)獲取當(dāng)前類的所有訂閱方法限府,再調(diào)用 subscribe(subscriber, subscriberMethod)這個(gè)方法夺颤,我們先看findSubscriberMethods(subscriberClass)做了什么事情;
     List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
       List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            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;
        }
    }
1. 從緩存中獲取訂閱類中的訂閱方法胁勺,如果緩存中有就返回世澜,沒有那么就根據(jù)ignoreGeneratedIndex這個(gè)標(biāo)志位來確定查找方法的邏輯,而這個(gè)變量的值就是在EventBusBuilder()中定義的署穗,默認(rèn)值為false 也就是說默認(rèn)是走findUsingInfo(subscriberClass)這個(gè)方法的寥裂,這個(gè)方法是優(yōu)先使用索引方式查找訂閱方法嵌洼,如果為true是通過反射的方式獲取訂閱方法,找到之后會(huì)將方法加入到緩存封恰,下次取出的時(shí)候就不需要通過反射獲取咱台。


        private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
            
            //...
            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);
            }  
        }


         private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
            FindState findState = prepareFindState();
            findState.initForSubscriber(subscriberClass);
            while (findState.clazz != null) {
                findUsingReflectionInSingleClass(findState);
                findState.moveToSuperclass();
            }
            return getMethodsAndRelease(findState);
        }

通過findstate里面的subscriberInfo獲取里面的方法,如果這個(gè)屬性為空俭驮,那么就通過findUsingReflectionInSingleClass(findState)這個(gè)方法來獲取訂閱方法,這個(gè)屬性的值是通過構(gòu)建EventBus對(duì)象傳遞的屬性值春贸,我們通過getDefault()方式獲取的EventBus這個(gè)屬性就是null混萝,傳入Builder對(duì)象來使用EventBus也不常用,所以我也沒有進(jìn)行深入研究萍恕。

         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 (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.(method, eventType)) {
                                ThreadMode threadMode = subscribeAnnotation.threadMode();
                                findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMod      e,
                                        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");
                }
            }
        }   

獲取訂閱類聲明的所有方法; 然后對(duì)獲取到的方法全部遍歷一遍
獲取方法的修飾符:即方法前面的public逸嘀、private等關(guān)鍵字。
如果該類方法使用了@subscribe標(biāo)注允粤、方法中只有一個(gè)參數(shù)崭倘、且方法修飾符為public。 findState.checkAdd(method, eventType) 如果之前沒有存在過則返回true
判斷@Subscribe標(biāo)注中的threadMode對(duì)應(yīng)的值类垫,默認(rèn)模式ThreadMode.POSTING
創(chuàng)建一個(gè)SubscriberMethod對(duì)象司光,該對(duì)象很簡(jiǎn)單就是保存有方法、方法參數(shù)類型悉患、線程模式残家、訂閱的優(yōu)先級(jí)、sticky標(biāo)志位售躁。與Retrofit類似只是這里創(chuàng)建了一個(gè)SubscriberMethod對(duì)象坞淮。并將該對(duì)象添加到FindSate的List集合中。
這樣就完成了通過訂閱類獲取訂閱的所有方法的過程陪捷,接下來就是調(diào)用 subscribe(subscriber, subscriberMethod)回窘;

        private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        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;
            }
        }

        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);

        if (subscriberMethod.sticky) {
            if (eventInheritance) {
                // Existing sticky events of all subclasses of eventType have to be considered.
                // Note: Iterating over all events may be inefficient with lots of sticky events,
                // thus data structure should be changed to allow a more efficient lookup
                // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
                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);
            }
        }
    }

獲取方法參數(shù)類型;注意:使用@Subscribe標(biāo)注的方法有且僅有一個(gè)參數(shù)
利用訂閱者對(duì)象及其事件處理方法構(gòu)建一個(gè)Subscription對(duì)象市袖,該對(duì)象存儲(chǔ)有Object啡直、SubscriberMethod對(duì)象
從subscriptionsByEventType集合中獲取當(dāng)前事件對(duì)應(yīng)的Subscription對(duì)象集合; 如果得到的集合為空則創(chuàng)建一個(gè) 這 樣的集合,并將剛創(chuàng)建的Subscription對(duì)象添加進(jìn)subscriptionsByEventType集合中凌盯;如果得到的集合不為空且 剛 創(chuàng)建的Subscription對(duì)象已經(jīng)存在該集合中則拋出異常付枫,即同一個(gè)對(duì)象不能注冊(cè)兩次!
將第二步創(chuàng)建的Subscription對(duì)象按照優(yōu)先級(jí)存入Subscription對(duì)象集合中驰怎,該集合中的元素都是按照優(yōu)先級(jí)從高到低存放.
以subscriber對(duì)象為鍵阐滩,從typesBySubscriber獲取該對(duì)象對(duì)應(yīng)的接收事件類型集合,沒有則創(chuàng)建一個(gè)這樣的集合县忌,然后當(dāng)前事件類型添加到該集合中掂榔,最后將整個(gè)集合添加進(jìn)typesBySubscriber集合中继效;有則直接添加到接收事件類型集合中;
該值默認(rèn)為false装获,除非在注冊(cè)事件方法時(shí)使用了如下的標(biāo)注@Subscribe(sticky = true)瑞信;那么就會(huì)執(zhí)行到這里。通過便利粘性事件Map集合找到對(duì)應(yīng)的方法穴豫,如果找到了粘性事件方法就會(huì)調(diào)用checkPostStickyEventToSubscription(newSubscription, stickyEvent)凡简,而這個(gè)方法內(nèi)部就是調(diào)用了EventBus.Post()這個(gè)方法。
接下來我們看他的Post過程

      public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get(); // 獲取到當(dāng)前線程的PostingThreadState 
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);  // 將發(fā)送的事件加到當(dāng)前線程的事件隊(duì)列中

        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();  // 判斷是不是在UI線程
            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;
            }
        }
    }

       final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<>();
        boolean isPosting;
        boolean isMainThread;
        Subscription subscription;
        Object event;
        boolean canceled;
    }

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

在Post方法中精肃,只是獲取到一個(gè)當(dāng)前線程的PostingThreadState秤涩,然后將事件添加到了事件隊(duì)列中,真正執(zhí)行post事件的還是通過 postSingleEvent(eventQueue.remove(0), postingState)

     private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); // 傳遞參數(shù)類型類的繼承的類司抱,以及所有接口
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); // 根據(jù)傳入?yún)?shù)的類型進(jìn)行查找所有的訂閱方法
            }
        } 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) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

在上面的方法中筐眷,只是找到所有的事件類的父類或者接口,并且通過postSingleEventForEventType(event, postingState, clazz)進(jìn)行處理习柠,根據(jù)處理結(jié)果判斷是否找到訂閱方法匀谣,沒有找到則根據(jù)是否需要打印log信息,打印log以及發(fā)送了一個(gè)沒有訂閱方法方法的事件

       private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {

        //...
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);  // subscriptionsByEventTypemap集合资溃,保存了發(fā)送的參數(shù)對(duì)應(yīng)的Class文件以及所有的事件處理者 武翎,這個(gè)方法是用來獲取所有訂閱了該改事件的處理者
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            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;
    }

獲取到了所有的事件處理者后就直接遍歷,調(diào)用 postToSubscription(subscription, event, postingState.isMainThread) 這個(gè)方法進(jìn)行處理
釋放對(duì)象中的資源

         private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
            switch (subscription.subscriberMethod.threadMode) {
                case POSTING:   // 在當(dāng)前發(fā)送的線程中執(zhí)行 肉拓, 不作處理
                    invokeSubscriber(subscription, event);
                    break;
                case MAIN:      // 在UI線程執(zhí)行后频,如果當(dāng)前是主線程,則直接不做處理 暖途,不是就通過mainThreadPoster 卑惜,post到主線程進(jìn)行處理
                    if (isMainThread) {
                        invokeSubscriber(subscription, event);
                    } else {
                        mainThreadPoster.enqueue(subscription, event);
                    }
                    break;
                case MAIN_ORDERED: // 相當(dāng)于主線程優(yōu)先,如果主線程的poster存在就在主線程執(zhí)行驻售,不然在當(dāng)前線程執(zhí)行
                    if (mainThreadPoster != null) {
                        mainThreadPoster.enqueue(subscription, event);
                    } else {
                        // temporary: technically not correct as poster not decoupled from subscriber
                        invokeSubscriber(subscription, event);
                    }
                    break;
                case BACKGROUND:    // 在子線程中執(zhí)行露久,如果為主線程就通過backgroundPoster去執(zhí)行,否則在當(dāng)前線程執(zhí)行
                    if (isMainThread) {
                        backgroundPoster.enqueue(subscription, event);
                    } else {
                        invokeSubscriber(subscription, event);
                    }
                    break;
                case ASYNC: // 在子線程中執(zhí)行欺栗,通過asyncPoster執(zhí)行
                    asyncPoster.enqueue(subscription, event);
                    break;
                default:
                    throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
            }
        }

根據(jù)當(dāng)前線程判斷以及需要執(zhí)行的線程判斷是在哪個(gè)線程執(zhí)行毫痕,如果不需要更改線程,則調(diào)用 invokeSubscriber(subscription, event) 迟几, 不然則通過每個(gè)線程的poster來執(zhí)行

        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        new HandlerPoster(eventBus, looper, 10);

        Object looperOrNull = getAndroidMainLooperOrNull();  // 獲取主線程的looper
        return looperOrNull == null ? null :
                new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);

        public class HandlerPoster extends Handler implements Poster {

            private final PendingPostQueue queue;
            private final int maxMillisInsideHandleMessage;
            private final EventBus eventBus;
            private boolean handlerActive;
        
            protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
                super(looper);
                this.eventBus = eventBus;
                this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
                queue = new PendingPostQueue();
            }
        
            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) {
                                // Check again, this time in synchronized
                                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;
                }
            }
        }

我們可以看到mainThreadPoster其實(shí)就是一個(gè)綁定了主線程的looper對(duì)象的Handler 通過handleMessage將消息傳回主線程處理

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) {
                                // Check again, this time in synchronized
                                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;
            }
        }
    
    }

BackgroundPoster內(nèi)部維護(hù)了一個(gè)消息隊(duì)列消请,執(zhí)行的時(shí)候從消息隊(duì)列中取出消息通過線程池進(jìn)行處理,而線程池是在EventBuilder中的參數(shù)类腮,在我們通過getDefault()傳入默認(rèn)的Builder時(shí)臊泰,其實(shí)已經(jīng)創(chuàng)建了一個(gè)默認(rèn)的線城池對(duì)象,某一時(shí)段內(nèi)BackgroundThread模式的事件都會(huì)在BackgroundPoster的run方法中排隊(duì)處理蚜枢,也就是說該時(shí)段內(nèi)的所有事件是在一個(gè)線程中排隊(duì)后串行執(zhí)行的(隊(duì)列中的事件處理完之后又有新的事件發(fā)布才會(huì)新開線程)

        ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
        private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool(); 

創(chuàng)建一個(gè)線程池缸逃,根據(jù)需要?jiǎng)?chuàng)建新線程针饥,但當(dāng)它們可用時(shí),將重用先前構(gòu)建的線程需频。這些池通常會(huì)提高執(zhí)行許多短命異步任務(wù)的程序的性能丁眼。調(diào)用{@代碼Exc}將重用以前構(gòu)建的線程,如果可用的話昭殉。如果沒有現(xiàn)有線程可用苞七,則將創(chuàng)建新線程并將其添加到池中。未使用六十秒的線程會(huì)終止挪丢。因此莽鸭,一個(gè)空閑時(shí)間足夠長(zhǎng)的池不要消耗任何資源

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

          void invokeSubscriber(PendingPost pendingPost) {
                Object event = pendingPost.event;
                Subscription subscription = pendingPost.subscription;
                PendingPost.releasePendingPost(pendingPost);
                if (subscription.active) {
                    invokeSubscriber(subscription, event);      // 最終還是執(zhí)行invokeSubscriber
                }
            }

AsyncPoster與BackgroundPoster類似 ,內(nèi)部維護(hù)了一個(gè)消息隊(duì)列吃靠,執(zhí)行的時(shí)候從消息隊(duì)列中取出消息通過線程池進(jìn)行處理,AsyncPoster同樣也是一個(gè)Runnable足淆,與Backgroundposter不同的是AsyncPoster并發(fā)度更高巢块,不是在一個(gè)線程中對(duì)隊(duì)列中的事件進(jìn)行串行處理,而是每一個(gè)新添加的任務(wù)都會(huì)在線程池中開辟一個(gè)新線程執(zhí)行
接下來看下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);
        }
    }

可以看到是通過反射執(zhí)行subscriberMethod族奢,到此為止訂閱方法才被執(zhí)行

  • EventBus 取消注冊(cè)流程

       public synchronized void unregister(Object subscriber) {
          List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); // 獲取到參數(shù)類型集合
          if (subscribedTypes != null) {
              for (Class<?> eventType : subscribedTypes) {
                  unsubscribeByEventType(subscriber, eventType);
              }
              typesBySubscriber.remove(subscriber);
          } else {
              logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
          }
      }
      
      可以看出通過訂閱類獲取到該類所有訂閱方法的參數(shù)類型集合,遍歷集合調(diào)用 unsubscribeByEventType(subscriber, eventType)丹鸿,并且移除當(dāng)前類的訂閱信息
    
    
      private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
          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;
                      subscriptions.remove(i);
                      i--;
                      size--;
                  }
              }
          }
      }
    
    
      final class Subscription {
          final Object subscriber;
          final SubscriberMethod subscriberMethod;
          /**
           * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
           * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
           */
          volatile boolean active;
      
          Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
              this.subscriber = subscriber;
              this.subscriberMethod = subscriberMethod;
              active = true;
          }
      
          @Override
          public boolean equals(Object other) {
              if (other instanceof Subscription) {
                  Subscription otherSubscription = (Subscription) other;
                  return subscriber == otherSubscription.subscriber
                          && subscriberMethod.equals(otherSubscription.subscriberMethod);
              } else {
                  return false;
              }
          }
      
          @Override
          public int hashCode() {
              return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
          }
      }
    

    并且將保存的訂閱方法從集合中移除越走,這樣就完成了取消訂閱過程

    到此為止EventBus源碼分析也到此結(jié)束,有的地方我也研究的不是很清楚靠欢,但是其實(shí)我們可以將它的流程看清楚廊敌,其實(shí)也很簡(jiǎn)單,就是注冊(cè)的時(shí)候找到注冊(cè)類內(nèi)的所有注冊(cè)方法门怪,形成一個(gè)一對(duì)多的映射關(guān)系骡澈,保存到集合中,再根據(jù)方法中的參數(shù)類型掷空,+ 方法名肋殴,與訂閱的類,也有一個(gè)映射關(guān)系坦弟,當(dāng)發(fā)送事件時(shí)护锤,就根據(jù)發(fā)送的事件參數(shù)類型,找到與之對(duì)應(yīng)的所有的類酿傍,并且獲取到每個(gè)類中訂閱該事件的方法信息烙懦,通過反射調(diào)用該方法就可以了。原理并不是很復(fù)雜拧粪。

遇到的問題 :

發(fā)送Int類型 接收失敗 
    : 由于反射Int參數(shù)類型反射獲取到的是它的包裝類類型修陡,而存入的時(shí)候沧侥,存入的是Int類型,所以接收不到

泛型被擦除

    : 加入?yún)?shù)是List<> + 泛型 由于反射獲取的類型只會(huì)是List類型魄鸦,所以通過參數(shù)類型匹配時(shí)宴杀,會(huì)匹配所有的list類型的參數(shù)方法,而不會(huì)管集合的泛型
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拾因,一起剝皮案震驚了整個(gè)濱河市旺罢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绢记,老刑警劉巖扁达,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蠢熄,居然都是意外死亡跪解,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門签孔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叉讥,“玉大人,你說我怎么就攤上這事饥追⊥疾郑” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵但绕,是天一觀的道長(zhǎng)救崔。 經(jīng)常有香客問我发魄,道長(zhǎng)戳寸,這世上最難降的妖魔是什么佳吞? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任作烟,我火速辦了婚禮毛好,結(jié)果婚禮上涩澡,老公的妹妹穿的比我還像新娘蹋砚。我一直安慰自己粉寞,他們只是感情好昌执,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布烛亦。 她就那樣靜靜地躺著,像睡著了一般懂拾。 火紅的嫁衣襯著肌膚如雪煤禽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天岖赋,我揣著相機(jī)與錄音檬果,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛选脊,可吹牛的內(nèi)容都是我干的杭抠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼恳啥,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼偏灿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起钝的,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤翁垂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后硝桩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沿猜,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年碗脊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了啼肩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡衙伶,死狀恐怖疟游,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情痕支,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布蛮原,位于F島的核電站卧须,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏儒陨。R本人自食惡果不足惜花嘶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蹦漠。 院中可真熱鬧椭员,春花似錦、人聲如沸笛园。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽研铆。三九已至埋同,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間棵红,已是汗流浹背凶赁。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人虱肄。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓致板,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親咏窿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子斟或,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 原文鏈接:http://blog.csdn.net/u012810020/article/details/7005...
    tinyjoy閱讀 547評(píng)論 1 5
  • 項(xiàng)目到了一定階段會(huì)出現(xiàn)一種甜蜜的負(fù)擔(dān):業(yè)務(wù)的不斷發(fā)展與人員的流動(dòng)性越來越大,代碼維護(hù)與測(cè)試回歸流程越來越繁瑣翰灾。這個(gè)...
    fdacc6a1e764閱讀 3,186評(píng)論 0 6
  • 先吐槽一下博客園的MarkDown編輯器缕粹,推出的時(shí)候還很高興博客園支持MarkDown了,試用了下發(fā)現(xiàn)支持不完善就...
    Ten_Minutes閱讀 563評(píng)論 0 2
  • 觀察者模式 自己對(duì)觀察者模式的理解:定義:Define a one-to-many dependency betw...
    安仔夏天勤奮閱讀 1,159評(píng)論 1 3
  • EventBus源碼分析 Android開發(fā)中我們最常用到的可以說就是EventBus了,今天我們來深入研究一下E...
    BlackFlag閱讀 509評(píng)論 3 4