EventBus3 源碼解讀

基本概念

EventBus是一款針對Android優化的發佈/訂閱事件總線庫。簡便了Activities, Fragments, 以及background threads之間的通信,使發送者與訂閱者之間有效解耦。
image_1ak28ro9staoi6p139u1bcg3889.png-43.9kB

基本使用

EventBus的使用也極其簡單,只需三步即可。

  1. 定義一個事件類型。

     public class MessageEvent {
     public final String message;
     public MessageEvent(String message) {
        this.message = message;
     }
    }
  2. 準備訂閱者
    只需給一個public方法添加@Subscribe註解,那麼當發佈事件時,訂閱者就能匹配並接受處理事件。

    // This method will be called when a MessageEvent is posted
    @Subscribe
    public void onMessageEvent(MessageEvent event){
    Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
    }
    
    // This method will be called when a SomeOtherEvent is posted
    @Subscribe
    public void handleSomethingElse(SomeOtherEvent event){
    doSomethingWith(event);
    }

    所有的訂閱者都應該在事件總線中被註冊。只有被註冊的訂閱者才能收到事件。

    @Override
    public void onStart() {
        super.onStart();
     EventBus.getDefault().register(this);
    }
    
    @Override
    public void onStop() {
      EventBus.getDefault().unregister(this);
     super.onStop();
    }
  3. 發佈事件
    你可以在代碼的任何地方發佈事件,所有更當前事件類型匹配的訂閱者都可以接收到這個事件。

     EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

EventBus是一個非常小巧的庫,但是功能卻足夠強大,接下來去源碼裏看看。

源碼解讀

我們從EventBus.getDefault().register(this);這一行開始,看看getDefault()做了什麼?

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

可以看出,保持了一個單例。EventBus的構造方法如下。

    //=================這兩個集合很重要,後面經常出現 START========================

    //key爲事件類型,value爲訂閱關係列表。用於查詢訂閱了該事件的所有訂閱關係列表,下稱事件類型集合
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    //key爲訂閱者,value爲訂閱者中的事件類型列表。用於查詢該訂閱者訂閱了的事件。下稱訂閱者集合
    private final Map<Object, List<Class<?>>> typesBySubscriber;

     //=======================這兩個集合很重要,後面經常出現 END==================

    //粘性事件,只保留最近一次的事件(相同事件類型只保留一次)
    private final Map<Class<?>, Object> stickyEvents;
    //存放SubscriberInfo索引
    private List<SubscriberInfoIndex> subscriberInfoIndexes;
    //事件類型緩存,key爲事件類型,value爲當前事件類型繼承的所有事件類型
    private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();

    //主線程發佈者
    private final HandlerPoster mainThreadPoster;
    //子線程發佈者(串行)
    private final BackgroundPoster backgroundPoster;
    //子線程發佈者(另開一個線程)
    private final AsyncPoster asyncPoster;
    //訂閱方法查找器
    private final SubscriberMethodFinder subscriberMethodFinder;
    //線程池,用於在子線程中發佈事件
    private final ExecutorService executorService;

    private final boolean throwSubscriberException;
    private final boolean logSubscriberExceptions;
    private final boolean logNoSubscriberMessages;
    private final boolean sendSubscriberExceptionEvent;
    private final boolean sendNoSubscriberEvent;
    private final boolean eventInheritance;

    private final int indexCount;

    public EventBus() {
        this(DEFAULT_BUILDER);
    }

    //構造方法
    EventBus(EventBusBuilder builder) {
        //初始化事件類型集合
        subscriptionsByEventType = new HashMap<>();
        //初始化訂閱者集合
        typesBySubscriber = new HashMap<>();
        //粘性事件集合
        stickyEvents = new ConcurrentHashMap<>();
        //主線程發佈者
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        //子線程發佈者(串行,保持只有一個線程)
        backgroundPoster = new BackgroundPoster(this);
        //子線程發佈者(並行,新起一個線程)
        asyncPoster = new AsyncPoster(this);

        //以下通過EventBusBuilder進行賦值
        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;
    }

代碼有點長,看的可能有點暈,從源碼可以看出最終構造方法中會傳入EventBusBuilder對象進行賦值初始化,EventBusBuilder用來配置信息。構造方法主要就是初始化環境。

註冊事件

我們現在就來看看register中的源碼。

    public void register(Object subscriber) {
        //獲取Class對象
        Class<?> subscriberClass = subscriber.getClass();
        //通過方法查找器尋找該訂閱者中的訂閱方法。
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                 //加入到集合中保存
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

代碼很簡練,思路也比較清晰。首先獲取訂閱者的Class對象,然後通過訂閱者方法查找器(SubscriberMethodFinder)查詢該訂閱者中的訂閱方法並返回,最後通過subscribe存入到相關集合中。

在介紹SubscriberMethodFinder之前我們先來了解一下其他幾個類。

Subscribe註解

Subscribe用來給訂閱方法進行註解,可以指定線程模型,優先級,是否粘性等等。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;
    boolean sticky() default false;
    int priority() default 0;
}

ThreadMode(線程模型)

ThreadMode是個枚舉類,可以指定四種線程模型。

public enum ThreadMode {
    //表示在哪個線程發佈事件就在哪個線程接收事件
    POSTING,
    //表示在主線程接收事件
    MAIN,
    //表示在子線程接收事件
    BACKGROUND,
    //表示開啓一個線程接收事件
    ASYNC
}

SubscriberMethod(訂閱者方法)

通過類名就可以猜出這個類肯定是用來包裝訂閱方法的,裏面存放了方法、線程模型、事件類型(訂閱方法中那個參數類型),優先級、是否粘性等。

public class SubscriberMethod {
    final Method method;//訂閱方法
    final ThreadMode threadMode;//線程模型
    final Class<?> eventType;//事件類型(就是訂閱方法的參數類型)
    final int priority;//優先級
    final boolean sticky;//是否粘性

    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;
    }
     //..
     //省略部分源碼
}

FindState

FindState是一個臨時存儲訂閱方法的類,在查找完畢後就會被回收。

    static class FindState {
        //存儲訂閱方法的集合
        final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
        //根據事件類型存儲訂閱方法,用來判斷是不是該事件已經被添加過了
        final Map<Class, Object> anyMethodByEventType = new HashMap<>();
        //根據方法名生成的key存儲訂閱者的類
        final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
        //方法key生成器
        final StringBuilder methodKeyBuilder = new StringBuilder(128);

        Class<?> subscriberClass;//訂閱者的父類
        Class<?> clazz;//當前訂閱者
        boolean skipSuperClasses;//是否跳過父類
        SubscriberInfo subscriberInfo;//這個用於註解生成器

       //初始化FindState
        void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false;
            subscriberInfo = null;
        }

      //回收FindState
        void recycle() {
            subscriberMethods.clear();
            anyMethodByEventType.clear();
            subscriberClassByMethodKey.clear();
            methodKeyBuilder.setLength(0);
            subscriberClass = null;
            clazz = null;
            skipSuperClasses = false;
            subscriberInfo = null;
        }
       //..
       //省略了部分源碼
    }

Subscription

Subscription表示訂閱關係,由訂閱者和訂閱者方法構成。

final class Subscription {
    final Object subscriber;//訂閱者
    final SubscriberMethod subscriberMethod;//訂閱者方法

    volatile boolean active;

    Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
        this.subscriber = subscriber;
        this.subscriberMethod = subscriberMethod;
        active = true;
    }
   //..
   //省略了部分源碼
}

註冊事件

現在我們回過頭來看看SubscriberMethodFinder的findSubscriberMethods方法。

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        //看看集合中有沒有緩存
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        //是否忽略註解器生成的Index類
        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;
        }
    }

一般如果不引用註解生成器,就會直接走反射查找這個路線。

    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        //獲取一個臨時保存訂閱信息的FindState類
        FindState findState = prepareFindState();
        //初始化基本信息(其實就是把subscriberClass賦值給findState.clazz)
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
             //查找訂閱方法
            findUsingReflectionInSingleClass(findState);
            //定位到父類(就是把父類賦值給findState.clazz,默認跳過系統類)
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);//從FindState類中取出方法集合,然後釋放資源。
    }

默認會保持4個FindState循環利用,prepareFindState就是取出一個FindState。然後通過findUsingReflectionInSingleClass將訂閱方法集合暫時保存在FindState中。

   private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            //反射獲取方法
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
         //循環遍歷所有的方法
        for (Method method : methods) {
            int modifiers = method.getModifiers();//獲取修飾符
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {//必須爲public
                Class<?>[] parameterTypes = method.getParameterTypes();獲取方法的參數類型。
                if (parameterTypes.length == 1) {//只能包含一個參數
                    //獲取Subscribe註解
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {
                        Class<?> eventType = parameterTypes[0];
                        //判斷是否沒有添加過
                        if (findState.checkAdd(method, eventType)) {
                            //獲取線程模型等信息
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            //添加到FindState中的subscriberMethods集合類
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                }
                //...
                //省略了else中的代碼
        }
    }

findUsingReflectionInSingleClass方法主要用於遍歷匹配方法,如果滿足條件就添加到FindState中的subscriberMethods集合進行保存。既然訂閱方法已經遍歷完了,那麼現在我們回到register方法中。
image_1ak32t2cv1c7e1luh18hprr0146t9.png-24.5kB
可以看出會對每個方法進行遍歷然後執行subscribe

    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        //獲取事件類型(就是方法裏的那個參數類型)
        Class<?> eventType = subscriberMethod.eventType;
         //用Subscription包裝subscriberMethod,可以看出將訂閱者與訂閱方法給關聯了起來。
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);

        //看看事件類型集合裏是不是存在過之前的事件類型( CopyOnWriteArrayList是線程安全的)
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {//沒有當前事件類型的集合
            //第一次須初始化列表
            subscriptions = new CopyOnWriteArrayList<>();
            //subscriptions爲空表示之前沒有相同的類型,那麼現在就塞進去
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            //subscriptions不爲空說明有相同事件類型的,判斷列表裏是不是已經包含了,包含就拋出異常
            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) {
           //沒有就給當前訂閱者new個事件列表放進去
            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);
            }
        }
    }

代碼有點長,但是邏輯並不複雜,可以看出把訂閱方法循環添加到了集合中。然後檢查有沒有粘性方法,如果有就將最近一次的粘性事件發佈即可。

解除事件

接下來看解除事件,爲什麼不先看發佈事件?因爲註冊和解除是互相呼應的,而且比較簡單。趁熱看,免得之後又被幾個集合給搞懵逼了(說的就是我)。

    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 {
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

我們知道,註冊事件時會將訂閱者以及訂閱事件保存到集合中,那麼解除事件毋容置疑,首先去集合中查詢有沒有,如果有,把它從事件類型集合中移除,然後從訂閱者集合中移除。unsubscribeByEventType源碼如下。

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

發佈事件

發佈事件用ThreadLocal保存了PostingThreadState,PostingThreadState是一個保存事件的類。然後通過循環發送單個事件,可以看出發佈事件是串行執行的。

    /** Posts the given event to the event bus. */
    public void post(Object event) {
       //PostingThreadState類似於FindState,用於保存要發佈的事件,裏面有一個事件隊列
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);//添加到事件隊列中

        if (!postingState.isPosting) {
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            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;
            }
        }
    }

PostingThreadState的源碼如下。

    final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<Object>();//事件列表
        boolean isPosting;//是否正在發佈事件
        boolean isMainThread;//是否在主線程
        Subscription subscription; //訂閱關係
        Object event; //事件
        boolean canceled;//是否已被取消
    }

接下來看看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);
        }
        //..
        //省略了部分源碼
    }

可以看出,最終通過postSingleEventForEventType來發布事件。

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

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.enqueue(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC:
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }

最終通過反射發佈事件。我們只來看一下POSTING源碼。其他就不贅述了,操作基本大同小異。

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

到此爲止,整個EventBus工作流程已經梳理完畢。

最後

  • 那個註解生成器是什麼鬼?

註解生成器,就是在編譯的時候根據註解生成特定的類。就跟自己寫的源碼一樣,執行效率比反射要高很多。
我們在分析subscriberMethodFinder.findSubscriberMethods查找方法時,提到一般只會走反射,所以沒有關心通過註解生成器查找的步驟。

        //是否忽略註解器生成的Index類
        if (ignoreGeneratedIndex) {
            //通過反射查找
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
           //通過註解生成器生成的類查找
            subscriberMethods = findUsingInfo(subscriberClass);
        }

現在我們來看下findUsingInfo源碼。

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        //初始化FindState
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);//獲取註解器生成的SubscriberInfo
            if (findState.subscriberInfo != null) {
                //如果找到了SubscriberInfo就獲取方法
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                //否則還是反射找
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

SubscriberInfo信息如下。

public interface SubscriberInfo {
    Class<?> getSubscriberClass();//獲取父類

    SubscriberMethod[] getSubscriberMethods();//獲取訂閱方法

    SubscriberInfo getSuperSubscriberInfo();//獲取父類訂閱者信息

    boolean shouldCheckSuperclass();
}

getSubscriberInfo用來根據訂閱者獲取SubscriberInfo。

    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;
            }
        }
        //SubscriberInfoIndex中獲取SubscriberInfo
        if (subscriberInfoIndexes != null) {
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

EventBus中註解生成器生成代碼。

   private void createInfoIndexFile(String index) {
        BufferedWriter writer = null;
        try {
            JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index);
            int period = index.lastIndexOf('.');
            String myPackage = period > 0 ? index.substring(0, period) : null;
            String clazz = index.substring(period + 1);
            writer = new BufferedWriter(sourceFile.openWriter());
            if (myPackage != null) {
                writer.write("package " + myPackage + ";\n\n");
            }
            writer.write("import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;\n");
            writer.write("import org.greenrobot.eventbus.meta.SubscriberMethodInfo;\n");
            writer.write("import org.greenrobot.eventbus.meta.SubscriberInfo;\n");
            writer.write("import org.greenrobot.eventbus.meta.SubscriberInfoIndex;\n\n");
            writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n");
            writer.write("import java.util.HashMap;\n");
            writer.write("import java.util.Map;\n\n");
            writer.write("/** This class is generated by EventBus, do not edit. */\n");
            writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n");
            writer.write("    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;\n\n");
            writer.write("    static {\n");
            writer.write("        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();\n\n");
            writeIndexLines(writer, myPackage);
            writer.write("    }\n\n");
            writer.write("    private static void putIndex(SubscriberInfo info) {\n");
            writer.write("        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);\n");
            writer.write("    }\n\n");
            writer.write("    @Override\n");
            writer.write("    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {\n");
            writer.write("        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);\n");
            writer.write("        if (info != null) {\n");
            writer.write("            return info;\n");
            writer.write("        } else {\n");
            writer.write("            return null;\n");
            writer.write("        }\n");
            writer.write("    }\n");
            writer.write("}\n");
        } catch (IOException e) {
            throw new RuntimeException("Could not write source for " + index, e);
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    //Silent
                }
            }
        }
    }

writeIndexLines寫入訂閱者相關的訂閱方法信息

    private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException {
        for (TypeElement subscriberTypeElement : methodsByClass.keySet()) {
            if (classesToSkip.contains(subscriberTypeElement)) {
                continue;
            }

            String subscriberClass = getClassString(subscriberTypeElement, myPackage);
            if (isVisible(myPackage, subscriberTypeElement)) {
                writeLine(writer, 2,
                        "putIndex(new SimpleSubscriberInfo(" + subscriberClass + ".class,",
                        "true,", "new SubscriberMethodInfo[] {");
                List<ExecutableElement> methods = methodsByClass.get(subscriberTypeElement);
                writeCreateSubscriberMethods(writer, methods, "new SubscriberMethodInfo", myPackage);
                writer.write("        }));\n\n");
            } else {
                writer.write("        // Subscriber not visible to index: " + subscriberClass + "\n");
            }
        }
    }

大家只要知道註解生成器是用來幹嘛的就行了,關於註解生成器的原理和使用方法,改篇再作深究,有興趣的可以自行查閱AnnotationProcessor資料。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章