萬人收藏淋肾!關(guān)于Android EventBus源碼解析硫麻,看這一篇就夠了!

  • 寫在前面:如果你看到這篇文章,希望你能夠自己對(duì)照著源碼走一遍,直接反射或者使用索引都會(huì)詳細(xì)分析使用的!

EventBus優(yōu)點(diǎn)和特性

  • 也許你有個(gè)疑問: 市面上有很多事件傳遞框架為何選擇EventBus,而不是Otto , Rxbus等,相比較他們都可以滿足日常開發(fā)需求,只是后兩者更新基本停滯,而EventBus還在正常更新維護(hù),選擇接入人數(shù)也是最多的,同時(shí)功能也是最全的,如果你選擇了使用該框架,自然了解源碼的運(yùn)行對(duì)于調(diào)試絕對(duì)是有幫助的!
  • 我們學(xué)知識(shí)不能簡簡單單只是會(huì)用而已,要知其然而知其所以然才能進(jìn)步,提升自己~
優(yōu)點(diǎn)
  • 簡化組件間的通信,解耦事件發(fā)送和接受者
  • 很好的應(yīng)用于Activity,Fragment之間,后臺(tái)線程之間的通信,避免使用多個(gè)Intent傳遞,handler通信等
  • 避免復(fù)雜的,易于出錯(cuò)的依賴和生命周期問題,比如多個(gè)Activity跳轉(zhuǎn)后的回調(diào)問題
  • 速度響應(yīng)快,尤其是3.0以后再編譯器增加索引
  • 輕量大概50K左右的jar包
  • 被大量的app所使用,在實(shí)際中被驗(yàn)證
  • 有很多的高級(jí)功能,如線程切換模式,訂閱的優(yōu)先級(jí)等
特性
  • 簡單易用的注解API : 簡單的@Subscribe注解放到訂閱方法上即可通過編譯期的訂閱者索引,app就可以不用在運(yùn)行期通過注解反射拿到訂閱了
  • 支持事件投遞到UI線程,不管事件是從哪個(gè)線程發(fā)送過來的
  • 支持事件和訂閱者的繼承關(guān)系: 如 事件A是事件B的父類,則發(fā)送B類型的事件,該事件也會(huì)發(fā)送給對(duì)于事件A感興趣的訂閱者,對(duì)于訂閱者也存在相似的繼承關(guān)系,可以通過eventInheritance(false)關(guān)閉該功能,只在本類中調(diào)用,父類接口不在回調(diào)的
  • 即可零設(shè)定EventBus直接工作,也可以通過構(gòu)建者模式調(diào)整EventBus的行為,滿足你的需求EventBusBuilder.builder()
//通過EventBusBuilder.builder()的方法構(gòu)建EventBusBuilder對(duì)象配置里面的信息以后調(diào)用build()方法創(chuàng)建
public EventBus build() { //創(chuàng)建一個(gè)EventBus對(duì)象
        return new EventBus(this);
    }
復(fù)制代碼
  • 注意:通過此方法可以創(chuàng)建多個(gè)EventBus對(duì)象,且每個(gè)配置信息不同,但是每個(gè)EventBus的實(shí)例都是獨(dú)立的,也就是說每個(gè)EventBus post事件,只要使用該EventBus注冊(cè)的訂閱者才能接收到,其他EventBus注冊(cè)的是無法接收的即在EventBus.getEventBus(type).regirst(this)的Activity或者Fragment中的方法都注冊(cè)到了該type返回的EventBus中啦!

EventBus的構(gòu)建

  • 首先分析該類的各個(gè)屬性含義
    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE =  Executors.newCachedThreadPool();
    ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; 
    //默認(rèn)線程池,是一個(gè)核心0,最大Max,無緩存隊(duì)列SynchronousQueue;如果大量事件一起發(fā)送可能導(dǎo)致OOM,一般需要更改一下線程池配置
    //通過build的方法executorService(executorService)傳遞進(jìn)來,主要用于異步和后臺(tái)事件傳遞

    ////在訂閱方法中拋出異常時(shí),是否打印日志,在類中注解重寫onSubscriberExceptionEvent可以監(jiān)聽到
    boolean logSubscriberExceptions = true; 
    //沒有找到訂閱方法,是否打印日志
    boolean logNoSubscriberMessages = true;
    //在非訂閱SubscriberExceptionEvent事件方法中拋出異常時(shí), 是否發(fā)送SubscriberExceptionEvent事件
    boolean sendSubscriberExceptionEvent = true;
    //沒找到事件訂閱方法,是否發(fā)送NoSubscriberEvent事件
    boolean sendNoSubscriberEvent = true;
    //在非訂閱SubscriberExceptionEvent事件方法中拋出異常時(shí), 是否拋出EventBusException異常, 默認(rèn)為false
    boolean throwSubscriberException;
    boolean eventInheritance = true; //發(fā)送子事件,是否發(fā)送父事件,默認(rèn)為true,最好改成false,避免不必要的麻煩

    //三個(gè)參數(shù)用于參照訂閱方法
    boolean ignoreGeneratedIndex;  //是否直接用反射查找訂閱方法(就是運(yùn)行期查找,速度慢耗時(shí),3.0以后優(yōu)化使用索引的),默認(rèn)是false
    boolean strictMethodVerification; //非注解生成索引時(shí),嚴(yán)格方法驗(yàn)證:當(dāng)方法不符合格式(public,非abstract, 非static,非橋接方法,只有一個(gè)參數(shù))時(shí),是否拋出EventBusException異常,默認(rèn)false
    List<SubscriberInfoIndex> subscriberInfoIndexes; //注解生成的索引,在編譯器生成,需要通過android-apt三方插件或annotationProcessor生成
    List<Class<?>> skipMethodVerificationForClasses; //檢查以onEvent開頭的方法,基本不用啦,都是使用注解自定義方法了
復(fù)制代碼
  • 注意: 對(duì)EventBus增加索引,必須在第一個(gè)EventBus.regirst之前,因此一般操作都是在Application的oncreate方法中添加

    //提高性能:第一點(diǎn)是關(guān)閉父類以及接口查找分發(fā)事件(只有本類調(diào)取,父類接口不在回調(diào))樊卓;
    //第二點(diǎn) 添加索引拿愧,索引添加的原理就是提前在編譯的時(shí)候加載好注冊(cè)類的相關(guān)信息。
    EventBus.builder().addIndex(new MyEventBusIndex()).eventInheritance(false).installDefaultEventBus(); 
    //EventBus.getDefault() 獲得的即為當(dāng)前installDefaultEventBus方法生成的,不會(huì)在重新創(chuàng)建了,但是如果通過builder.build()重新構(gòu)建的EventBus就無效了!
    復(fù)制代碼
    
  • 這里我們主要通過Event3.0的源碼,畢竟用新不用舊嘛

注解Subscribe
  • 通過注解標(biāo)記訂閱方法:同時(shí)可以指定threadMode,代表該訂閱方法運(yùn)行的線程,指定sticky,代表是否是粘性事件,指定priority代表優(yōu)先級(jí)(由高到底依次接收,可以更改設(shè)置)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;
    boolean sticky() default false;
    int priority() default 0;
}
復(fù)制代碼
  1. threadMode: 訂閱方法運(yùn)行的線程
    • ThreadMode.POSTING —— POST線程碌尔,訂閱方法運(yùn)行在發(fā)布者所在的線程(默認(rèn))
    • ThreadMode.MAIN —— UI主線程浇辜,訂閱方法運(yùn)行在主線程,發(fā)送如果是UI線程直接運(yùn)行,如果不是通過Handler回調(diào)到UI線程運(yùn)行
    • ThreadMode.BACKGROUND —— 后臺(tái)線程,發(fā)布者是主線程唾戚,訂閱方法運(yùn)行在新開子線程柳洋;發(fā)布者是子線程,訂閱方法運(yùn)行在發(fā)布者所在的線程叹坦;(通過線程池創(chuàng)建子線程)
    • ThreadMode.ASYNC —— 異步線程熊镣,訂閱方法運(yùn)行在新開子線程,無論發(fā)布者是在哪個(gè)線程(同上共用一個(gè)線程池)
  2. sticky: 與Android廣播中的sticky概念一致,表示如果當(dāng)前還未注冊(cè),則通過postSticky發(fā)送的廣播將會(huì)保存在內(nèi)存中,當(dāng)有注冊(cè)時(shí)就會(huì)法將該粘性事件傳遞給訂閱者,即先發(fā)送后訂閱是可以接收到的!
  3. priority:訂閱優(yōu)先級(jí),事件發(fā)送以后根據(jù)優(yōu)先級(jí)傳遞,相同優(yōu)先級(jí)根據(jù)訂閱順序傳遞(添加由大->小,調(diào)取方法直接輪詢由0 -> size從而達(dá)到事件傳遞性,且事件對(duì)象不可變但屬性值可變從而可以更改值的傳遞)

注冊(cè)register

  • EventBus通過register注冊(cè)到Activity或Fragment中
public void register(Object subscriber) { //subscriber表示this
    Class<?> subscriberClass = subscriber.getClass(); //獲取this代表的類
    List<SubscriberMethod> subscriberMethods =  subscriberMethodFinder.findSubscriberMethods(subscriberClass); //查找訂閱者類中的所有訂閱方法
       synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

//SubscriberMethod類的屬性
public class SubscriberMethod {
    final Method method;  //訂閱方法
    final ThreadMode threadMode; //訂閱方法在哪個(gè)線程執(zhí)行
    final Class<?> eventType; //事件類
    final int priority; //優(yōu)先級(jí)
    final boolean sticky; //是否是粘性
    /** Used for efficient comparison */
    String methodString;
復(fù)制代碼
  • 看一下 subscriberMethodFinder.findSubscriberMethods如何查找訂閱方法
//首先肯定是subscriberMethodFinder的創(chuàng)建:在EventBus的構(gòu)造函數(shù)
 subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex); //注意里面?zhèn)鬟f的參數(shù): 索引,方法驗(yàn)證是否符合,是否使用反射調(diào)用

//引入EventBus的第一個(gè)緩存map集合: 鍵表示當(dāng)前注冊(cè)類activity或者Fragment,值表示當(dāng)前類中的訂閱方法的集合
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) { //如果注冊(cè)類已經(jīng)緩存過了,直接返回
            return subscriberMethods;
        }
//ignoreGeneratedIndex表示使用反射也就是忽略注解器編譯器生成的MyEventBusIndex類,默認(rèn)是false
        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass); //通過反射調(diào)用,在運(yùn)行期
        } else { //我們都會(huì)添加編譯器生成的代碼邏輯
            subscriberMethods = findUsingInfo(subscriberClass);//// 從注解器生成的MyEventBusIndex類中獲得訂閱類的訂閱方法信息
        }
        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); //調(diào)用完成以后添加到緩存中
            return subscriberMethods;
        }
    }
復(fù)制代碼
  1. 首先我們先看通過反射來獲取訂閱類中的訂閱方法信息findUsingReflection,通過索引獲取的稍后解釋
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        FindState findState = prepareFindState(); 
        findState.initForSubscriber(subscriberClass);//從數(shù)組長度為4中取值并初始化Findstate
        while (findState.clazz != null) {
            findUsingReflectionInSingleClass(findState); //找到類中的所有事件響應(yīng)方法
            findState.moveToSuperclass(); //繼續(xù)尋找當(dāng)前類父類中注冊(cè)的事件響應(yīng)方法
        }
        return getMethodsAndRelease(findState);
    }
復(fù)制代碼
  1. 查找類中的所有事件響應(yīng)方法
private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // 獲取類中的所有方法,包括私有方法
            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(); //獲取方法的屬性,private,static等
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { //如果方法時(shí)public,且不是abstract,static,bridge, synthetic編譯器生成的
                Class<?>[] parameterTypes = method.getParameterTypes();//獲取方法參數(shù),且參數(shù)只有1個(gè)
                if (parameterTypes.length == 1) {
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); //獲取以Subscribe注解的方法
                    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())); //將一個(gè)類中的所有訂閱方法都加入到findstate的集合中
                        }
                    }
                } 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");
            }
        }
    }

復(fù)制代碼
  1. 我們看一下FindState類的屬性
//FindState是SubscriberMethodFinder的靜態(tài)內(nèi)部類,類不長,我們都拿過來吧
    static class FindState {
        final List<SubscriberMethod> subscriberMethods = new ArrayList<>(); //訂閱方法信息列表
        final Map<Class, Object> anyMethodByEventType = new HashMap<>(); //以事件類型為key,方法信息為value的集合
        final Map<String, Class> subscriberClassByMethodKey = new HashMap<>(); //以methodkey為key,訂閱者類為value集合 (下方的methodkey : method方法所在的類)
        final StringBuilder methodKeyBuilder = new StringBuilder(128); //生成methodkey
        //methodkey 是由method名字,事件類名稱組成
        Class<?> subscriberClass;  //訂閱者類
        Class<?> clazz;
        boolean skipSuperClasses; //是否跳過父類
        SubscriberInfo subscriberInfo;

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

        void recycle() {
            subscriberMethods.clear();
            anyMethodByEventType.clear();
            subscriberClassByMethodKey.clear();
            methodKeyBuilder.setLength(0);
            subscriberClass = null;
            clazz = null;
            skipSuperClasses = false;
            subscriberInfo = null;
        }

        //檢查訂閱者中注冊(cè)的事件響應(yīng)是否可以合法的加入到訂閱方法信息中,分為兩層檢查
        boolean checkAdd(Method method, Class<?> eventType) { //method是訂閱方法,eventType是事件類
            // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
            // Usually a subscriber doesn't have methods listening to the same event type.
            //第一次檢查同一事件類型下是否已有訂閱方法信息了
            Object existing = anyMethodByEventType.put(eventType, method);
            if (existing == null) { //沒有就添加成功
                return true;
            } else {
                //如果當(dāng)前事件類型在同一個(gè)類中對(duì)應(yīng)多個(gè)方法,則檢查他們方法簽名是否一致
                if (existing instanceof Method) { //existing是相同的鍵對(duì)應(yīng)的oldValue
                    if (!checkAddWithMethodSignature((Method) existing, eventType)) {
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    // Put any non-Method object to "consume" the existing Method
                    anyMethodByEventType.put(eventType, this); //方法簽名不一致(一個(gè)類中多個(gè)方法中含有同一個(gè)事件類)添加FindState作為value
                }
                return checkAddWithMethodSignature(method, eventType);
            }
        }
        //使用訂閱方法簽名檢測是否可以加入訂閱方法信息列表中,method訂閱方法,eventType事件類
        private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
            methodKeyBuilder.setLength(0);
            methodKeyBuilder.append(method.getName());
            methodKeyBuilder.append('>').append(eventType.getName());
            //方法簽名methodkey怎么生成的
            String methodKey = methodKeyBuilder.toString();
            Class<?> methodClass = method.getDeclaringClass(); //方法所在的類
            Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass); 
            if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) //methodClass是MethodClassOld的子類或者子接口 
            {
                //如果不存在同樣方法簽名的訂閱方法或 之前保存的訂閱方法所在的類為當(dāng)前將要添加的訂閱方法所在的類的子類(目前不存在此情況募书,因?yàn)橹粫?huì)從子類向父類查找)绪囱,則可以合法添加此訂閱方法信息
                return true;
            } else { 
                // 存在同樣方法簽名,且methodOld是子類
                //subscriberClassByMethodKey只保存父子繼承關(guān)系的最下層子類,目的是為了在子類注冊(cè)監(jiān)聽事件時(shí)莹捡,如果父類中有相同的事件響應(yīng)方法鬼吵,應(yīng)該調(diào)用子類的覆寫方法
                subscriberClassByMethodKey.put(methodKey, methodClassOld);
                return false;
            }
        }

        void moveToSuperclass() {
            if (skipSuperClasses) {
                clazz = null;
            } else {
                clazz = clazz.getSuperclass();
                String clazzName = clazz.getName();
                /** Skip system classes, this just degrades performance. */
                if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
                    clazz = null;
                }
            }
        }
    }
復(fù)制代碼
  • 以上對(duì)于FindState中的步驟為:
    1. 通過反射獲取class的所有方法
    2. 過濾掉不是public和是abstract,static,bridge,synthetic的方法,且參數(shù)只有一個(gè)的
    3. 找出別subScribe注解修飾的方法
    4. 將method和事件類型添加到findState中
    5. 將所有的method訂閱方法封裝成SubscribeMethod添加到findState中集合類中
    6. 這就是查詢訂閱方法的步驟,下面接著上文,繼續(xù)注冊(cè)步驟!
  1. 我們目光從新回到注冊(cè)邏輯上面來
  public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); //上面已經(jīng)具體分析了,如何去找到該類中的所有訂閱方法
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);  //遍歷方法調(diào)取
            }
        }
    }
復(fù)制代碼
  1. 我們看subscribe(subscriber, subscriberMethod) 參數(shù): 當(dāng)前訂閱類, 訂閱類中的訂閱方法
    // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType; //訂閱方法的事件類
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod); //創(chuàng)建一個(gè)訂閱類的封裝,注意參數(shù)
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); //從緩存中根據(jù)事件類獲取訂閱類的封裝集合
        if (subscriptions == null) { //從中查找,如果不存在就添加進(jìn)入,如果存在集合且集合中已經(jīng)添加過了拋出異常,不能添加多次
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            if (subscriptions.contains(newSubscription)) { //如果已經(jīng)存在
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }

        int size = subscriptions.size(); //遍歷已經(jīng)存在的集合,根據(jù)他們的優(yōu)先級(jí)排序添加
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { //優(yōu)先級(jí)由大到小排序
                subscriptions.add(i, newSubscription);
                break;
            }
        }
        //typesBySubscriber緩存的是key:當(dāng)前訂閱類activity/fragment, value:當(dāng)前類中的訂閱方法的事件集合
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents); 
        }
        subscribedEvents.add(eventType); //在當(dāng)前訂閱方法集合中加入當(dāng)前事件

        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(); //查找當(dāng)前是當(dāng)前事件是緩存事件的父類則也會(huì)調(diào)用它的子類
                for (Map.Entry<Class<?>, Object> entry : entries) {
                    Class<?> candidateEventType = entry.getKey();
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent); //在注冊(cè)的時(shí)候就開始調(diào)用訂閱方法了,如果緩存隊(duì)列中存在
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

    //checkPostStickyEventToSubscription
    private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        if (stickyEvent != null) {
            // 一會(huì)兒post的時(shí)候還要研究這個(gè)方法
            postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
        }
    }

    //new的一個(gè)訂閱類 Subscription 屬性包括
    final class Subscription {
    final Object subscriber; // 訂閱者對(duì)象
    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; // 是否處于激活狀態(tài).如果不激活就不運(yùn)行哦

    Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
        this.subscriber = subscriber;
        this.subscriberMethod = subscriberMethod;
        active = true; //新建的肯定是激活狀態(tài)
    }

    @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();
    }
}
復(fù)制代碼
  • 總結(jié)訂閱方法: 由于上方已經(jīng)總結(jié)了對(duì)于一個(gè)訂閱類查找到它之中的所有訂閱方法以后循環(huán)調(diào)用subscribe繼續(xù)注冊(cè)
    1. 創(chuàng)建一個(gè)訂閱類,判斷是否存在以當(dāng)前事件為key的List<訂閱類>的集合,就是將所有相同的事件的訂閱類統(tǒng)一管理,這樣發(fā)送一個(gè)事件,只需要遍歷該集合即可知道回調(diào)那些類的哪些方法
    2. 注意加入到List集合時(shí)根據(jù)優(yōu)先級(jí)排序,由大到小,調(diào)用順序也是如此即可實(shí)現(xiàn)優(yōu)先級(jí)發(fā)送事件啦
    3. 對(duì)于訂閱類通過typesBySubscriber緩存: key當(dāng)前訂閱類,value:當(dāng)前訂閱類中所有事件類的集合
    4. 如果是粘性事件,判斷是否需要調(diào)取事件父類或接口對(duì)應(yīng)的訂閱方法,如果true且緩存中存在該事件的post,則直接執(zhí)行訂閱方法,否則只執(zhí)行當(dāng)前類中的訂閱方法(達(dá)到了先發(fā)送,后訂閱,且訂閱即運(yùn)行的目的,可以在Fragment中不通過intent對(duì)重新打開的Activity傳遞信息)

反注冊(cè)u(píng)nregister

  • 有訂閱對(duì)應(yīng)的就有反注冊(cè),否則會(huì)內(nèi)存泄漏且多次注冊(cè)相同信息源碼中報(bào)錯(cuò)的
  • 我們先思考一下,上方注冊(cè)的時(shí)候主要有兩個(gè)map集合,
    1. ypesBySubscriber表示key:訂閱類,value:訂閱類中的所有的事件類型集合;
    2. subscriptionsByEventType表示key: 事件類型 , value: 所有注冊(cè)該事件的訂閱方法集合
    3. 舉個(gè)例子,朋友圈A和B是好友,如果A要取關(guān)B,則A中有map(A , List好友們),在A中查找List好友將B刪除,同時(shí)在B中找到他的好友列表將A刪除即可啦
    • 同樣的,對(duì)于上方兩個(gè)集合來說:我們也是反注冊(cè)時(shí)通過this訂閱類在ypesBySubscriber集合中找到該訂閱類中的所有事件類型的集合后,遍歷在subscriptionsByEventType中找到以當(dāng)前事件為key的value,訂閱方法集合中刪除該類對(duì)應(yīng)的訂閱方法即可啦
public synchronized void unregister(Object subscriber) {
       List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); //通過訂閱類獲取他當(dāng)中的所有訂閱事件類,我們加入的時(shí)候時(shí)加入事件類的class
       if (subscribedTypes != null) {
           for (Class<?> eventType : subscribedTypes) { //遍歷訂閱事件,開始解綁另外一個(gè)集合中的數(shù)據(jù):以eventType為key中刪除
               unsubscribeByEventType(subscriber, eventType);
           }
           typesBySubscriber.remove(subscriber); //從當(dāng)前訂閱類為key的map移除
       } else {
           Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
       }
   }

private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
       List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); //獲取以當(dāng)前事件為key的所有訂閱方法集合
       if (subscriptions != null) {
           int size = subscriptions.size();
           for (int i = 0; i < size; i++) {
               Subscription subscription = subscriptions.get(i);
               if (subscription.subscriber == subscriber) { //遍歷如果事件是在當(dāng)前類中訂閱的,則從訂閱方法集合中刪除,因?yàn)檫@個(gè)類就要over啦,自然也就不用再接受訂閱事件啦
                   subscription.active = false; //標(biāo)記不激活
                   subscriptions.remove(i); //從訂閱方法集合中刪除
                   i--;
                   size--;
               }
           }
       }
   }
復(fù)制代碼

post發(fā)送事件

  • 通過上面的注冊(cè)和反注冊(cè)已經(jīng)將事件,訂閱方法都添加到集合中了,我們就可以發(fā)送一個(gè)事件開始響應(yīng)方法啦!
  • 小知識(shí)點(diǎn): ThreadLocal是線程隔離的只有同一線程才能獲取值,通過get訪問,其他線程獲取不到的,同一個(gè)線程中才能獲取,且同一個(gè)線程獲取的是同一個(gè)對(duì)象
//ThreadLocal 的get方法
   public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t); //如果已經(jīng)存在map則返回map中的值
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    //調(diào)用initialValue創(chuàng)建一個(gè)對(duì)象值,存儲(chǔ)到map中,下次直接通過get即可獲取
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

//上面簡單分析了ThreadLocal的源碼,下面開始真正的post操作

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() { //如果調(diào)用get方法沒有value值通過這個(gè)方法新建一個(gè)返回的,下次改線程在調(diào)用,已經(jīng)存在直接返回了,達(dá)到了對(duì)象的線程唯一性
            return new PostingThreadState();
        }
    };

 public void post(Object event) {
 //代碼很短小,第一行就蒙蔽了,不急,就是上面我們說了get函數(shù)
        PostingThreadState postingState = currentPostingThreadState.get(); //不同線程對(duì)應(yīng)不同的postingState,相同的線程之間遵循h(huán)appended-before
        List<Object> eventQueue = postingState.eventQueue; //postingState中的eventQueue隊(duì)列
        eventQueue.add(event); //將事件添加到隊(duì)列中:每個(gè)post線程的隊(duì)列都是相互獨(dú)立的
        //isPosting默認(rèn)false,可以進(jìn)去
        if (!postingState.isPosting) { //相同線程是遵循h(huán)appended-before規(guī)則的,是安全的
        //是否是主進(jìn)程
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            postingState.isPosting = true; //阻擋不要在進(jìn)來了,表示當(dāng)前線程正在處理發(fā)送事件
            if (postingState.canceled) { //沒有別取消事件
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                while (!eventQueue.isEmpty()) { //輪詢開始發(fā)送事件
                    postSingleEvent(eventQueue.remove(0), postingState); //隊(duì)列,先進(jìn)先出
                }
            } finally {
                postingState.isPosting = false; //完成恢復(fù)默認(rèn)可以在接受發(fā)送信息
                postingState.isMainThread = false;
            }
        }
    }
//靜態(tài)內(nèi)部類:每個(gè)線程獨(dú)一份
final static class PostingThreadState {
    //事件隊(duì)列
    final List<Object> eventQueue = new ArrayList<Object>();
    boolean isPosting;
    boolean isMainThread;
    Subscription subscription;
    Object event;
    boolean canceled;
}
復(fù)制代碼
  • post流程
    1. 首先通過ThreadLocal獲取當(dāng)前線程中狀態(tài)PostingState,注意不同的線程擁有不同的狀態(tài)PostingState
    2. 將發(fā)送的event加入到PostingState類中的隊(duì)列中
    3. 循環(huán)遍歷事件隊(duì)列,發(fā)送單個(gè)事件調(diào)用
  • 發(fā)送單個(gè)Event的方法postSingleEvent
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass(); //獲取事件類型
        boolean subscriptionFound = false;
        if (eventInheritance) { //如果允許事件繼承,默認(rèn)允許
            //找到eventClass的所有父類和實(shí)現(xiàn)接口
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                // 依次向 eventClass 的父類或接口的訂閱方法發(fā)送事件
                // 只要有一個(gè)事件發(fā)送成功,返回 true 道盏,那么 subscriptionFound 就為 true
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
        //不允許繼承,那么只發(fā)送該事件
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }

        if (!subscriptionFound) { //如果當(dāng)前沒有訂閱者訂閱
            if (logNoSubscriberMessages) { 
                Log.d(TAG, "No subscribers registered for event " + eventClass);
            }
            //默認(rèn)允許的
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event)); //發(fā)送NosubSribeEvent事件,可以重寫訂閱方法接受到從而做自己的處理邏輯
            }
        }
    }

//postSingleEventForEventType(event, postingState, eventClass)參數(shù): 事件對(duì)象里面可能有值, 當(dāng)前線程的狀態(tài)postingState, 事件類型class 
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass); //獲取以當(dāng)前事件為key的訂閱類的集合(屬性: 訂閱類,訂閱方法,是否激活)
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) { //還記得添加由大->小,這里取值是由0->size實(shí)現(xiàn)優(yōu)先級(jí),同時(shí)event對(duì)象不可變,但是每個(gè)共用同一個(gè)event,里面的屬性值是可以更改的
                postingState.event = event;
                postingState.subscription = subscription; 
                boolean aborted = false;
                try {
                //發(fā)送事件,參數(shù)subscription訂閱類信息,event發(fā)送事件對(duì)象, 是否是主線程
                    postToSubscription(subscription, event, postingState.isMainThread);
                    //是否被取消了
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null; //回復(fù)默認(rèn)值
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) { // 如果被取消而柑,則跳出循環(huán)
                    break;
                }
            }
            return true; //有一個(gè)發(fā)送成功即可,對(duì)應(yīng)上面的判斷
        }
        return false;
    }

//postToSubscription: isMainThread 表示發(fā)送方法是否在主線程中
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) { //接受事件的訂閱方法所在的線程
            case POSTING: //那個(gè)線程發(fā)送就在那個(gè)線程接受
                invokeSubscriber(subscription, event);
                break;
            case MAIN: 
                if (isMainThread) {
                    invokeSubscriber(subscription, event); //在主線程中接受
                } else { //其他線程向主線程發(fā)送添加到隊(duì)列(鏈表)后通過Handler一次發(fā)送隊(duì)列中的值給UI線程最終調(diào)用的還是invokeSubscriber(subscription, event)方法
                //PendingPost添加隊(duì)列獲取是通過PendingPost對(duì)象池,同Message相同的
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) { //如果在子線程中發(fā)送,則隨機(jī)開辟一條子線程接收
                    backgroundPoster.enqueue(subscription, event);
                } else { //在子線程中發(fā)送,在相同的線程中接收
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC: //無論是UI還是子線程,都會(huì)開辟一個(gè)新的線程接收
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }

    //invokeSubscriber參數(shù): subscription訂閱類信息: 訂閱類,方法,是否激活信息
    void invokeSubscriber(Subscription subscription, Object event) {
        try {
        //反射調(diào)用方法: method.invoke(class, 參數(shù)信息)即可,在哪個(gè)線程調(diào)用就運(yùn)行在哪個(gè)線程
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause()); //如果沒有找到就發(fā)送錯(cuò)誤事件,重寫即可監(jiān)聽到
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }
復(fù)制代碼
  • 我們看一下線程之間是如何做的吧!
  1. 主線程的mainThreadPoster.equeue()
//在EventBus中創(chuàng)建的
 mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
 final class HandlerPoster extends Handler {

    private final PendingPostQueue queue; //事件隊(duì)列
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        queue = new PendingPostQueue();  //每個(gè)線程都有他自己的時(shí)間隊(duì)列
    }

    void enqueue(Subscription subscription, Object event) {
    //獲取很有意思,所有線程共用同一個(gè)對(duì)象池,當(dāng)存在可用返回,否則新建,回收的時(shí)候添加到池中,了解過Message消息對(duì)象的很熟悉啦
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);  //加入隊(duì)列
            if (!handlerActive) {
                handlerActive = true;
                if (!sendMessage(obtainMessage())) { //發(fā)送事件封裝類
                    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); //UI線程取出來調(diào)用invokeSubscriber方法
                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;
        }
    }
}

//Event中的方法
    void invokeSubscriber(PendingPost pendingPost) {
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        PendingPost.releasePendingPost(pendingPost); //回收對(duì)象到對(duì)象池中以便下一個(gè)運(yùn)用
        if (subscription.active) { //如果當(dāng)前激活狀態(tài),則反射調(diào)用方法即可
            invokeSubscriber(subscription, event);
        }
    }

//類的靜態(tài)常量,所有線程共用同一個(gè)
private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();
復(fù)制代碼
  • 直到現(xiàn)在我們還沒有用到線程池的概念吧,這個(gè)時(shí)候你是不是都忘記了EventBus構(gòu)造函數(shù)中創(chuàng)建了一個(gè)線程池newCacheExecutor() 可能導(dǎo)致OOM,看一下backgroundPoster.enqueue(subscription, event);
//EventBus構(gòu)造函數(shù)中創(chuàng)建
backgroundPoster = new BackgroundPoster(this);
final class BackgroundPoster implements Runnable { //代碼量不多,整個(gè)拿過來

    private final PendingPostQueue queue; //時(shí)間隊(duì)列
    private final EventBus eventBus;

    private volatile boolean executorRunning;

    BackgroundPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
    //通過事件封裝對(duì)象池獲取對(duì)象
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost); //添加一個(gè)到隊(duì)列中,下面就可以執(zhí)行了
            if (!executorRunning) { //線程池是否正在運(yùn)行
                executorRunning = true;
                //調(diào)用EventBus中創(chuàng)建的線程池執(zhí)行該類的run方法
                eventBus.getExecutorService().execute(this);
            }
        }
    }

    @Override
    public void run() {
        try {
            try {
                while (true) {
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) { //雙重檢索隊(duì)列中還沒有新加則退出,開始回收線程
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    //線程池的一個(gè)線中程執(zhí)行方法,同上方的Ui線程一致的,反射調(diào)用執(zhí)行方法即可,無非就是運(yùn)行線程不同,這個(gè)是子線程,上面的是UI線程
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

}

// asyncPoster.enqueue(subscription, event);同樣是在EventBus構(gòu)造方法中創(chuàng)建的
class AsyncPoster implements Runnable { //類比較簡單

    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(); //通過子線程直接運(yùn)行即可
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }

}

復(fù)制代碼
  • 通過上面分析,equeue添加是一個(gè)個(gè)添加,一個(gè)個(gè)執(zhí)行,通過executorRunning變量控制著,如果run執(zhí)行中耗時(shí)過長,添加的特別迅速,線程池將會(huì)創(chuàng)建大量線程,最終可能OOM
  • Posting: 表示post線程在哪兒發(fā)送,接受的就是該線程
  • Main: 如果在主線程中發(fā)送,則直接執(zhí)行接受,否則利用Handler回調(diào)到主線程中執(zhí)行
  • BackGround子線程: 如果發(fā)布事件在主線程,則調(diào)用線程池中的一個(gè)子線程去執(zhí)行,否則直接在發(fā)送線程中執(zhí)行
  • (ASYNC)異步線程: 無論發(fā)布事件是UI還是子線程都利用一個(gè)異步線程來執(zhí)行!
  • 注意:以上所有的方法分析都是在Post()方法內(nèi)部調(diào)用邏輯,所以線程切換需要注意是否是線程池創(chuàng)建還是原來的post方法所在的線程之內(nèi)

配置索引

  • EventBus3.0以后為了提高效率避免在運(yùn)行期通過反射來做以上大量的工作,使用了索引配置生成類,可以在編譯器生成注冊(cè)文件,從而提升效率
  1. 使用:兩種方式:使用android-apt三方插件,或者annotationProcessor
//1.使用android-apt
buildscript {
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

apply plugin: 'com.neenbedankt.android-apt'

dependencies {
    compile 'org.greenrobot:eventbus:3.0.0'
    apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}

apt {
    arguments {
        eventBusIndex "com.monster.android.wild.MyEventBusIndex"
    }
}
//2\. 使用annotationProcessor
android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [eventBusIndex:'com.monster.android.wild.MyEventBusIndex']
            }
        }
    }
}

dependencies {
    compile 'org.greenrobot:eventbus:3.0.0'
    annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}  
復(fù)制代碼
  • com.monster.android.wild.MyEventBusIndex就是我們想要生成的Subscriber Index類
public class MyEventBusIndex implements SubscriberInfoIndex {
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX; //緩存mao:key當(dāng)前訂閱類 , 值是封裝的SimpleSubscriberInfo類(訂閱類,應(yīng)該檢查父類,該訂閱類中對(duì)應(yīng)的訂閱方法的數(shù)組)

    static {
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();

        // 從以上createInfoIndexFile()的實(shí)現(xiàn)來看,除了類名MyEventBusIndex荷逞,只有這一段代碼是非hardcode媒咳。編譯器自動(dòng)生成的代碼
        // 以訂閱者類為單位,將該訂閱者類中的所有訂閱函數(shù)以及相關(guān)參數(shù)种远,封裝到SimpleSubscriberInfo類對(duì)象中涩澡,
        // 以供EventBus在注冊(cè)過程中使用。注意SimpleSubscriberInfo類對(duì)象是在編譯時(shí)期就生成的坠敷,
        // 因而在運(yùn)行時(shí)期可以直接使用妙同,省去了運(yùn)行時(shí)期通過反射做相似操作的時(shí)間和資源消耗射富,從而提高效率,這里就是全文的精髓所在粥帚。
        putIndex(new SimpleSubscriberInfo(com.monster.android.wild.myeventbusdemo.MainActivity.class, true,
                new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onEvent",
                    com.monster.android.wild.myeventbusdemo.MainActivity.EventBusEvent.class, ThreadMode.MAIN),
        }));

    }

    private static void putIndex(SubscriberInfo info) {
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }

    // 將會(huì)在EventBus在注冊(cè)過程中使用胰耗,等會(huì)大家會(huì)看到
    @Override
    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }
}
復(fù)制代碼
  1. 上面register中有兩個(gè)分支,通過ignoreGeneratedIndex是否直接使用反射調(diào)用區(qū)分,我們當(dāng)時(shí)走的是第一個(gè)findUsingReflection,下面看添加索引后的第二個(gè)方法findUsingInfo
 private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass); //findstate數(shù)組中準(zhǔn)備并初始化FindState對(duì)象
        while (findState.clazz != null) {
        //重點(diǎn),重點(diǎn),重點(diǎn): 通過索引獲取編譯器生成的訂閱者信息
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) { //注意這里的subscriberInfo實(shí)際上是系統(tǒng)自動(dòng)生成的類SimpleSubscriberInfo對(duì)象 //如果找到了就遍歷訂閱類中的訂閱方法數(shù)組加入進(jìn)去
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); //調(diào)用SimpleSubscriberInfo.getSubscriberMethods方法獲取訂閱方法集合封裝成SubscriberMethod[]
                for (SubscriberMethod subscriberMethod : array) { //輪詢,下面就跟反射是一致的操作了
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else { //否則還是老實(shí)的回到反射注冊(cè)上面去吧
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState); //回收findState對(duì)象,以便下次使用
    }

 //getSubscriberInfo
 private SubscriberInfo getSubscriberInfo(FindState findState) {
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) { //新建的findState為null
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }
        //subscriberInfoIndexes是在合適創(chuàng)建的
        if (subscriberInfoIndexes != null) { //subscriberInfoIndexes可能添加多個(gè)文件信息,這里我們只是一個(gè)
            for (SubscriberInfoIndex index : subscriberInfoIndexes) { 
            //拿到唯一的一個(gè)index類即index為: MyEventBusIndex類對(duì)象
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz); //調(diào)用它的getSubscriberInfo(訂閱類)即可獲得已經(jīng)put進(jìn)緩存SUBSCRIBER_INDEX中的方法封裝類SimpleSubscriberInfo
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

    //通過EventBus構(gòu)造函數(shù)中創(chuàng)建通過build傳遞進(jìn)來的,如果我們使用索引并且重寫build方法傳遞進(jìn)來數(shù)據(jù)了
    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
    //將索引值穿進(jìn)去
    EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();
復(fù)制代碼
  • 至此:無論是直接反射注冊(cè)還是通過添加索引在編譯器生成文件運(yùn)行期直接讀取注冊(cè)都分析完成了,不知道你明白了沒有呢?最后的話也整理了一份《Android相關(guān)源碼精編解析》,方便大家筆記學(xué)習(xí),有需要的朋友可以點(diǎn)贊+評(píng)論支持下,然后評(píng)論留言或私信我獲取!



?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市芒涡,隨后出現(xiàn)的幾起案子柴灯,更是在濱河造成了極大的恐慌,老刑警劉巖费尽,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赠群,死亡現(xiàn)場離奇詭異,居然都是意外死亡旱幼,警方通過查閱死者的電腦和手機(jī)查描,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柏卤,“玉大人冬三,你說我怎么就攤上這事∶凭桑” “怎么了长豁?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長忙灼。 經(jī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
  • 文/蒼蘭香墨 我猛地睜開眼柒桑,長吁一口氣:“原來是場噩夢啊……” “哼弊决!你這毒婦竟也來了?” 一聲冷哼從身側(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ú)居荒郊野嶺守林人離奇死亡蒸走,尸身上長有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
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人之拨。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓茉继,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蚀乔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子烁竭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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