EventBus3.1.1源碼學習

此文章是建立在已經掌握EventBus的使用方法基礎上的,不會的參考官網

我們通過2步來講解,首先是注冊、接收回調與發送消息,然后講解一下解除注冊

第一步:

1、注冊類:注冊與回調方法

EventBus.getDefault().register(this);

    /**
     * 注解回調的方法
     * @param messageEvent
     */
  @Subscribe(threadMode = ThreadMode.MAIN)
  public void optionEvent(MessageEvent messageEvent){
      textView.setText(messageEvent.getMessage());
  }

此時我們查看一下源碼

public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

我們知道注冊時回調的方法名是可以隨便起的,原因就是上面第3句(findSubscriberMethods),有一個方法可以遍歷處理此類的所有使用過@Subscribe此注解的方法集合。
接著可以看到,下面是遍歷所有需要回調的方法集,調用了subscribe方法,我們來看一下此方法,代碼太長我們貼主要代碼

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

這里我們看到有一個subscriptionsByEventType成員變量,此變量是以EventType為key,而Value是Subscription集合,我們通過源碼可以看到,這里是通過EventType把所有注冊類下面相同參數的方法進行了分組。
也就是說注冊類下面有幾個接收回調的方法,就有幾個Subscription類對象,而且同一個類可以寫多個相同結果回調方法,方法名可以不同,源碼都會先進行分組后放進subscriptionsByEventType集合中。
2、發送消息

MessageEvent messageEvent = new MessageEvent(editText.getText().toString());
EventBus.getDefault().post(messageEvent);

我們看一下源碼

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            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);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }

我們可以看到,這里就是遍歷subscriptionsByEventType此集合,通過傳入的EventType得到所有注冊過以此方法為參數的對象,通過反射調用對象下面的方法。

第二步:取消注冊

EventBus.getDefault().unregister(this);

我們看一下源碼

public synchronized void unregister(Object subscriber) {
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        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());
        }
    }

我們可以看到,取消注冊是通過遍歷typesBySubscriber集合,來把添加到subscriptionsByEventType集合的數值移除掉,然后再從typesBySubscriber移除掉(因為注冊傳入的是this,所以一定要進行解除注冊,否則會造成內存泄漏),我們回頭在看一下typesBySubscriber集合,是在注冊時集合加入的

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

此集合是以注冊類對象為key,EventType為value進行存儲,目的就是為了解除注冊時方便從subscriptionsByEventType集合中移除注冊的方法。

講到這里,整個EventBus處理的流程是講完了,這次是第一次完整的自己分析源碼,講一下感受:
當我們要研究一個項目的源碼時,開始一定要先會使用此項目,然后通過使用的入口,進行Debug查看調用流程,然后看源碼的時候剛開始不要太細鉆研每個調用方法是干什么用的,要先理清整個脈絡,然后再回頭單塊攻克主要的成員變量是干什么用的,為什么這么用,如果理不清楚,可以用筆寫一下,每個值是干什么用的,真的很有用!!
最后貼一下我梳理時的筆記,字有點丑介意的話,請....你懂得


eventBus總結.jpg
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容