事件總線框架-EventBus源碼解析

只有越來越強(qiáng)大轿秧,才能越來越童話哼鬓∷妥牵——《美人魚》

前言

該系列以源碼閱讀為主青伤,框架基礎(chǔ)使用請(qǐng)自行查看官方文檔督怜。另源碼基于3.2.0版本

第一步:獲取Eventbus實(shí)例

使用Eventbus前需要先獲取Eventbus實(shí)例,獲取方式有兩種狠角,下面分開來分析源碼(這部分的邏輯比較簡(jiǎn)單号杠,請(qǐng)仔細(xì)源碼源碼注釋部分為后文理解打基礎(chǔ)):

方式一:EventBus.getDefault()

其源碼如下:

public class EventBus {
    
    public static String TAG = "EventBus";
    //單例模式下的默認(rèn)實(shí)例
    static volatile EventBus defaultInstance;
    //默認(rèn)EventBusBuilder實(shí)例
    private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
    //事件類型緩存集合
    private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
    //事件訂閱集合,key:訂閱的事件類型,value:訂閱這個(gè)事件的所有訂閱者集合
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    //訂閱者類型的集合,key:訂閱者對(duì)象,value:這個(gè)訂閱者訂閱的事件集合
    private final Map<Object, List<Class<?>>> typesBySubscriber;
    //粘性事件集合,粘性事件就是指訂閱者注冊(cè)事件后姨蟋,會(huì)發(fā)送一次最近發(fā)生的事件屉凯。key:粘性事件類型, value:事件對(duì)象
    private final Map<Class<?>, Object> stickyEvents;
    //currentPostingThreadState是一個(gè)ThreadLocal,他的特點(diǎn)是獲取當(dāng)前線程一份獨(dú)有的變量數(shù)據(jù)眼溶,不受其他線程影響悠砚。
    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };

    // @Nullable Eventbus支持Android和Java,這個(gè)在Android中堂飞,用來標(biāo)記Android的UI線程
    private final MainThreadSupport mainThreadSupport;
    // 1 @Nullable 主線程的poster灌旧,獲取主線程的loop,通過handler執(zhí)行
    private final Poster mainThreadPoster;
    // 2 Background線程的poster(通過Executors.newCachedThreadPool()一個(gè)事件一個(gè)事件執(zhí)行绰筛。)
    private final BackgroundPoster backgroundPoster;
    // 3 事件異步處理的poster
    private final AsyncPoster asyncPoster;
    //訂閱者響應(yīng)函數(shù)信息存儲(chǔ)和查找類
    private final SubscriberMethodFinder subscriberMethodFinder;
    //ExecutorService是Executor直接的擴(kuò)展接口节榜,也是最常用的線程池接口
    //Eventbus中設(shè)置其默認(rèn)的值為Executors.newCachedThreadPool(),源碼見EventBusBuilder類中的private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
    private final ExecutorService executorService;
    //以下為EventBusBuilder類中的成員變量,在EventBusBuilder類中加以說明
    private final boolean throwSubscriberException;
    private final boolean logSubscriberExceptions;
    private final boolean logNoSubscriberMessages;
    private final boolean sendSubscriberExceptionEvent;
    private final boolean sendNoSubscriberEvent;
    private final boolean eventInheritance;
    //是EventBuilder.subscriberInfoIndexes.size()的值别智,即subscriberInfo索引數(shù)量宗苍,subscriberInfoIndexes是什么會(huì)在后面講解
    private final int indexCount;
    //日志管理類
    private final Logger logger;
    
    /** 使用單例便捷創(chuàng)建進(jìn)程范圍內(nèi)EventBus實(shí)例*/
    public static EventBus getDefault() {
        EventBus instance = defaultInstance;
        if (instance == null) {
            synchronized (EventBus.class) {
                instance = EventBus.defaultInstance;
                if (instance == null) {
                    instance = EventBus.defaultInstance = new EventBus();
                }
            }
        }
        return instance;
    }

    public EventBus() {
        //4
        this(DEFAULT_BUILDER);
    }
    //5
    EventBus(EventBusBuilder builder) {
        logger = builder.getLogger();
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        //返回持有UI線程looper的MainThreadSupport對(duì)象
        mainThreadSupport = builder.getMainThreadSupport();
        //構(gòu)建與主線程通信的HandlerPoster對(duì)象
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        backgroundPoster = new BackgroundPoster(this);
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        //構(gòu)建SubscriberMethodFinder實(shí)例,由下文EventBusBuilder 源碼可知ignoreGeneratedIndex默認(rèn)為false薄榛,即默認(rèn)SubscriberMethodFinder查找訂閱方法時(shí)不能忽略注解器生成的MyEventBusIndex索引
        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;
    }
...
}

可見EventBus 內(nèi)部使用雙重檢查加鎖實(shí)現(xiàn)了進(jìn)程范圍的單例模式讳窟,其中注釋1、2敞恋、3處分別創(chuàng)建了三個(gè)線程模型丽啡,他們是實(shí)現(xiàn)發(fā)送和處理消息線程切換的關(guān)鍵,關(guān)于他們的講解在后面給出硬猫。注釋4處可見其會(huì)以new EventBusBuilder()作為參數(shù)來調(diào)用注釋兒處的構(gòu)造方法补箍,而EventBusBuilder()源碼為空構(gòu)造函數(shù),所以通過EventBus.getDefault()方法獲取實(shí)例是以EventBusBuilder成員變量的默認(rèn)值以及EventBus成員變量的默認(rèn)值去構(gòu)建EventBus實(shí)例啸蜜。

方式二:通過EventBus.builder().build()構(gòu)建實(shí)例

很明顯坑雅,此方式為通過構(gòu)建者模式去獲取實(shí)例,當(dāng)你希望自定義參數(shù)設(shè)置時(shí)可使用該方法衬横,EventBus.builder()源碼如下:

public static EventBusBuilder builder() {
        return new EventBusBuilder();
    }

再來看EventBusBuilder類的源碼(同樣請(qǐng)仔細(xì)閱讀注釋部分裹粤,幫助理解后文):

public class EventBusBuilder {
    //EventBus內(nèi)部默認(rèn)維護(hù)的線程池
    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
    //訂閱者異常日志是否開啟,默認(rèn)為true
    boolean logSubscriberExceptions = true;
    //沒有訂閱者消息異常是否開啟蜂林,默認(rèn)為true
    boolean logNoSubscriberMessages = true;
    //是否發(fā)送訂閱者事件異常,默認(rèn)為true
    boolean sendSubscriberExceptionEvent = true;
    //如果沒有訂閱者是否發(fā)送事件,默認(rèn)為true
    boolean sendNoSubscriberEvent = true;
    //是否拋出訂閱者異常遥诉,默認(rèn)false
    boolean throwSubscriberException;
    //有繼承關(guān)系的事件的訂閱者是否接收該事件,默認(rèn)為true
    boolean eventInheritance = true;
    // 1 是否忽略注解器生成的MyEventBusIndex索引噪叙,默認(rèn)為false(注解生成器EventBusAnnotationProcessor為3.0以后新增特性矮锈,其可以在編譯期讀取@Subscribe()注解并且解析其中所包含的信息,以供運(yùn)行時(shí)直接使用睁蕾,從而運(yùn)行時(shí)的性能大大提高了)
    boolean ignoreGeneratedIndex;
    //是否開啟方法嚴(yán)格驗(yàn)證,默認(rèn)為false
    boolean strictMethodVerification;
    //在ThreadMode.ASYNC模式下默認(rèn)的線程池
    ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
    //不進(jìn)行方法驗(yàn)證的類的集合
    List<Class<?>> skipMethodVerificationForClasses;
    //訂閱者索引信息集合
    List<SubscriberInfoIndex> subscriberInfoIndexes;
    //日志管理者
    Logger logger;
    //Eventbus支持Android和Java苞笨,這個(gè)在Android中,用來標(biāo)記Android的UI線程
    MainThreadSupport mainThreadSupport;

    EventBusBuilder() {
    }

    public EventBus build() {
        return new EventBus(this);
    }
  ...
  //對(duì)以onEvent開頭的方法進(jìn)行方法名稱驗(yàn)證,以避免輸入錯(cuò)誤猫缭; 使用此方法葱弟,可以從此檢查中排除訂閱者類型壹店。 同時(shí)禁用對(duì)方法修飾符(公共猜丹,非靜態(tài)或抽象)的檢查
  public EventBusBuilder skipMethodVerificationFor(Class<?> clazz) {
        if (skipMethodVerificationForClasses == null) {
            skipMethodVerificationForClasses = new ArrayList<>();
        }
        skipMethodVerificationForClasses.add(clazz);
        return this;
    }
  /** 添加由EventBus的注釋預(yù)處理器生成的索引。 */
    public EventBusBuilder addIndex(SubscriberInfoIndex index) {
        if (subscriberInfoIndexes == null) {
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }
  
  MainThreadSupport getMainThreadSupport() {
        //如果我們自己傳入了MainThreadSupport則直接返回
        if (mainThreadSupport != null) {
            return mainThreadSupport;
         //這里isAndroidLogAvailable方法判斷Android SDK里包含android.util.Log類沒有
        } else if (Logger.AndroidLogger.isAndroidLogAvailable()) {
        //通過getAndroidMainLooperOrNull方法取得一個(gè)主線程的消息循環(huán)對(duì)象硅卢,該方法只是調(diào)用了 Looper.getMainLooper()
            Object looperOrNull = getAndroidMainLooperOrNull();
            //不為空則利用這個(gè)消息循環(huán)對(duì)象構(gòu)建出AndroidHandlerMainThreadSupport對(duì)象射窒,也就是MainThreadSupport的子類
            return looperOrNull == null ? null :
                    new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
        } else {
            return null;
        }
    }
  static Object getAndroidMainLooperOrNull() {
        try {
            return Looper.getMainLooper();
        } catch (RuntimeException e) {
            // Not really a functional Android (e.g. "Stub!" maven dependencies)
            return null;
        }
    }
  //將當(dāng)前設(shè)置應(yīng)用于 Default EventBus
  public EventBus installDefaultEventBus() {
        synchronized (EventBus.class) {
            if (EventBus.defaultInstance != null) {
                throw new EventBusException("Default instance already exists." +
                        " It may be only set once before it's used the first time to ensure consistent behavior.");
            }
            EventBus.defaultInstance = build();
            return EventBus.defaultInstance;
        }
    }
  
    public EventBus build() {
        return new EventBus(this);
    }
}

省略代碼為其成員變量的設(shè)置方法,在調(diào)用build()方法前可以調(diào)用這些方法來自定義成員變量的值将塑。在調(diào)用build() 方法時(shí)又會(huì)去調(diào)用上面注釋5中的EventBus(EventBusBuilder builder) 方法脉顿,所以這種方式構(gòu)建實(shí)例其實(shí)只是比第一種多了一步EventBusBuilder參數(shù)的自定義步驟。其中注釋1處的注解生成器EventBusAnnotationProcessor為3.0以后新增特性用以優(yōu)化其性能点寥,其可以在編譯期讀取@Subscribe()注解并且解析其中所包含的信息生成MyEventBusIndex類我們稱之為訂閱者索引艾疟,以供運(yùn)行時(shí)直接使用,從而使運(yùn)行時(shí)的性能大大提高了敢辩,我們通常使用EventBus時(shí)不會(huì)去設(shè)置該功能蔽莱,關(guān)于注解生成器的作用在后面部分再加以補(bǔ)充,我們先重點(diǎn)關(guān)注EventBus的整體邏輯實(shí)現(xiàn)戚长。
總結(jié):兩種方式本質(zhì)相同盗冷,只是第一種方式下使用默認(rèn)設(shè)置,第二種方式可自定義EventBusBuilder參數(shù)設(shè)置

第二步:得到eventbus對(duì)象后進(jìn)行注冊(cè)訂閱

注冊(cè)代碼eventBus.register(this)同廉,其源碼如下:

/**
     * 注冊(cè)監(jiān)聽者去接收事件. 監(jiān)聽者在對(duì)事件不感興趣時(shí)必須調(diào)用unregister(Object)方法來取消監(jiān)聽
     * 訂閱方法必須使用@Subscribe進(jìn)行標(biāo)注仪糖,同時(shí)可以設(shè)置@ThreadMode以及優(yōu)先級(jí)
     */
    public void register(Object subscriber) {
        //首先獲取注冊(cè)的對(duì)象的類型
        Class<?> subscriberClass = subscriber.getClass();
        //1然后獲取注冊(cè)的對(duì)象的訂閱方法
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        //2對(duì)當(dāng)前實(shí)例加鎖并循環(huán)注冊(cè)訂閱方法
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                // 對(duì)訂閱方法進(jìn)行注冊(cè)訂閱
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

代碼邏輯注釋已寫出,這里的SubscriberMethod封裝了訂閱方法(使用@Subscribe注解的方法)的信息迫肖,其源碼如下所示:

public class SubscriberMethod {
    final Method method;// 訂閱方法
    final ThreadMode threadMode; // 標(biāo)識(shí)在哪個(gè)線程執(zhí)行锅劝,有POSTING,MAIN,BACKGROUND,ASYNC 四種模式
    final Class<?> eventType; // 事件類型
    final int priority;// 優(yōu)先級(jí)
    final boolean sticky;//是否為粘性事件
    /** Used for efficient comparison */
    String methodString;

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

可見蟆湖,在SubscriberMethod類中鸠天,主要用來保存@Subscribe注解的訂閱方法的Method對(duì)象、線程模式帐姻、事件類型稠集、優(yōu)先級(jí)、是否是黏性事件等屬性饥瓷。接著來看上面register(Object subscriber)源碼中注釋1部分的邏輯剥纷,其通過subscriberMethodFinder.findSubscriberMethods(Class<?> subscriberClass)方法從注冊(cè)者類中找出并返回了所有訂閱方法的SubscriberMethod實(shí)例組成的列表,來看看該方法的源碼:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        // 這里首先從緩存當(dāng)中嘗試去取該訂閱者的訂閱方法
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
        // 當(dāng)緩存中沒有找到該訂閱者的訂閱方法的時(shí)候使用下面的兩種方法獲取方法信息
        //ignoreGeneratedIndex參數(shù)表示是否忽略注解器生成的MyEventBusIndex索引呢铆,該值默認(rèn)為false
        if (ignoreGeneratedIndex) {
            //如果 ignoreGeneratedIndex為true 就通過反射獲取訂閱方法信息
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            //如果ignoreGeneratedIndex為false晦鞋,通過EventBusAnnotationProcessor(注解處理器)生成的MyEventBusIndex中獲取訂閱方法信息
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        //如果未找到訂閱方法則報(bào)錯(cuò)
        if (subscriberMethods.isEmpty()) {
            throw new EventBusException("Subscriber " + subscriberClass
                    + " and its super classes have no public methods with the @Subscribe annotation");
        } else {
            //將找到的訂閱方法放置到緩存當(dāng)中
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

代碼邏輯注釋已注明,其中ignoreGeneratedIndex默認(rèn)為false,這在前面EventBus(EventBusBuilder builder) 方法中已經(jīng)分析過了,那么我們就先來看看ignoreGeneratedIndex為false時(shí)執(zhí)行的findUsingInfo(subscriberClass)的源碼:

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        // 通過FindState對(duì)象來存儲(chǔ)找到的方法信息
        FindState findState = prepareFindState();
        // 初始化FindState
        findState.initForSubscriber(subscriberClass);
        // 從當(dāng)前類開始循環(huán)遍歷該類的所有父類
        while (findState.clazz != null) {
            // 1 如果我們通過EventBusBuilder配置了MyEventBusIndex悠垛,便會(huì)通過getSubscriberInfo(findState)方法獲取到subscriberInfo 线定,通常情況下我們使用EventBus時(shí)并沒有配置
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {
                // 如果使用了MyEventBusIndex,將會(huì)進(jìn)入到這里并獲取訂閱方法信息
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                // 2 未使用MyEventBusIndex將會(huì)進(jìn)入這里使用反射獲取訂閱方法信息
                findUsingReflectionInSingleClass(findState);
            }
            // 將findState.clazz設(shè)置為當(dāng)前的findState.clazz的父類
            findState.moveToSuperclass();
        }
        //返回查找到的所有訂閱信息并釋放FindState對(duì)象
        return getMethodsAndRelease(findState);
    }

這里注釋1處先通過prepareFindState()找到方法信息并封裝成FindState對(duì)象存儲(chǔ)起來确买,先來看看FindState類的源碼定義:

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的集合
        final StringBuilder methodKeyBuilder = new StringBuilder(128); // 生成methodkey的stringbuilder

        Class<?> subscriberClass; // 訂閱者類
        Class<?> clazz; 
        boolean skipSuperClasses; // 是否跳過父類
        SubscriberInfo subscriberInfo; 
        //初始化訂閱者類下的FindState
        void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false;
            subscriberInfo = null;
        }
        //回收FindState占用的資源斤讥,釋放內(nèi)存
        void recycle() {
            subscriberMethods.clear();
            anyMethodByEventType.clear();
            subscriberClassByMethodKey.clear();
            methodKeyBuilder.setLength(0);
            subscriberClass = null;
            clazz = null;
            skipSuperClasses = false;
            subscriberInfo = null;
        }
    // checkAdd這部分的作用是檢測(cè)訂閱者中注冊(cè)的事件響應(yīng)方法是否可以合法的加入到訂閱方法信息中,分為兩層檢查
        boolean checkAdd(Method method, Class<?> eventType) {
            //第一層檢查同一事件類型下是否已有訂閱方法信息
            Object existing = anyMethodByEventType.put(eventType, method);
            if (existing == null) {
                return true;//如果還未有訂閱方法監(jiān)聽此事件湾趾,則可添加此訂閱方法信息
            } else {
                if (existing instanceof Method) {
                // 檢測(cè)到同一事件類型下已經(jīng)有訂閱事件響應(yīng)方法芭商,則繼續(xù)進(jìn)行第二層方法簽名的檢查
                    if (!checkAddWithMethodSignature((Method) existing, eventType)) {
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    // Put any non-Method object to "consume" the existing Method
                    anyMethodByEventType.put(eventType, this);
                }
                return checkAddWithMethodSignature(method, eventType);
            }
        }
        // 使用訂閱方法簽名檢測(cè)是否可以加入訂閱方法信息列表
        private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
            methodKeyBuilder.setLength(0);
            methodKeyBuilder.append(method.getName());
            methodKeyBuilder.append('>').append(eventType.getName());//使用訂閱方法名以及訂閱事件類型構(gòu)造methordKey

            String methodKey = methodKeyBuilder.toString();
            Class<?> methodClass = method.getDeclaringClass();
            Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass); //判斷是否存方法簽名相同的事件響應(yīng)方法,并比較相同方法簽名的訂閱方法所在類的關(guān)系
            if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
                // Only add if not already found in a sub class
                // 如果不存在同樣方法簽名的訂閱方法或者搀缠,之前保存的訂閱方法所在的類為當(dāng)前將要添加的訂閱方法所在的類的子類(目前不存在此情況铛楣,因?yàn)橹粫?huì)從子類向父類查找),則可以合法添加此訂閱方法信息
                return true;
            } else {
                // Revert the put, old class is further down the class hierarchy
                //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;
                }
            }
        }
    }

可見其主要用來幫助從訂閱者類中查找出訂閱方法信息并封裝起來岸浑,其中方法用于條件校驗(yàn)及查找訂閱者類的父類。這里不多做分析缴罗≈觯回到上面findUsingInfo(Class<?> subscriberClass)源碼中,通過注釋1可知通常我們會(huì)走到注釋2邏輯中面氓,來看看findUsingReflectionInSingleClass(findState)方法的源碼:

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();
            // 找到所有聲明為 public 的方法
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                Class<?>[] parameterTypes = method.getParameterTypes(); // 找到方法參數(shù)并且參數(shù)數(shù)量為1
                if (parameterTypes.length == 1) {
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); // 得到注解兵钮,并將方法添加到訂閱信息中去
                    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()));
                        }
                    }
                } 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");
            }
        }
    }

可見其邏輯為:

  1. 通過反射得到當(dāng)前 class 的所有方法
  2. 過濾掉不是 public 和是 abstract、static舌界、bridge掘譬、synthetic 的方法
  3. 找出所有參數(shù)只有一個(gè)的方法
  4. 找出被Subscribe注解的方法
  5. 把method 方法和 事件類型eventtype添加到 findState 中
  6. 把 method 方法、事件類型呻拌、threadMode葱轩、priority、sticky 封裝成 SubscriberMethod 對(duì)象藐握,然后添加到 findState.subscriberMethods
    這里我們?cè)倩氐絝indSubscriberMethods(Class<?> subscriberClass) 源碼中靴拱,如果 ignoreGeneratedIndex為true 就是忽略注解生成器生成的訂閱者索引MyEventBusIndex類,便會(huì)運(yùn)行findUsingReflection(subscriberClass)方法猾普,來看其源碼:
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        // 通過FindState對(duì)象來存儲(chǔ)找到的方法信息
        FindState findState = prepareFindState(); 
        findState.initForSubscriber(subscriberClass); // 初始化FindState
        while (findState.clazz != null) { 
            findUsingReflectionInSingleClass(findState);// 尋找某個(gè)類中的所有事件響應(yīng)方法
            findState.moveToSuperclass(); //繼續(xù)尋找當(dāng)前類父類中注冊(cè)的事件響應(yīng)方法
        }
         //返回查找到的所有訂閱信息并釋放FindState對(duì)象
        return getMethodsAndRelease(findState);
    }

可見其邏輯與findUsingInfo(Class<?> subscriberClass)方法的邏輯基本相同袜炕,只是findUsingInfo(Class<?> subscriberClass)多一個(gè)判斷我們使用EventBusBuilder時(shí)是否配置了MyEventBusIndex的邏輯,如果我們沒有配置MyEventBusIndex其之后邏輯與findUsingReflection邏輯相同初家,都是通過findUsingReflectionInSingleClass(findState)方法通過反射獲取訂閱方法信息的偎窘。所以我們了解到要使用訂閱者索引MyEventBusIndex必須同時(shí)滿足兩個(gè)條件乌助,一是ignoreGeneratedIndex為false(其默認(rèn)為false,EventBus默認(rèn)推薦我們使用訂閱者索引)陌知,二是我們使用EventBus時(shí)通過EventBusBuilder配置了MyEventBusIndex他托。通過訂閱者索引MyEventBusIndex我們能更高效的查找到訂閱者方法的信息,但我們重點(diǎn)關(guān)注EventBus的實(shí)現(xiàn)邏輯仆葡,先暫且不論性能問題赏参,不論使不使用訂閱者索引MyEventBusIndex我們都拿到了訂閱者方法信息并封裝了起來,接下來回到上面的register(Object subscriber) 源碼看注釋2后面的邏輯浙芙,其拿到所有訂閱方法后會(huì)去遍歷并通過subscribe(subscriber, subscriberMethod)方法訂閱所有訂閱方法登刺,subscribe(subscriber, subscriberMethod)源碼如下:

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType; // 獲取訂閱方法的事件類
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod); // 創(chuàng)建訂閱類
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); // 獲取訂閱了此事件類的所有訂閱者信息列表籽腕,如果不存在則將其加入訂閱者信息列表嗡呼,如果已經(jīng)存在此訂閱者信息則拋出已注冊(cè)的異常
        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;
            }
        }
        // 將訂閱者信息按照優(yōu)先級(jí)加入到訂閱者信息列表中
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); // 獲取此訂閱者實(shí)例訂閱的所有事件類的列表
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType); // 將此事件類加入 訂閱者事件類列表中
        // 判斷是否是粘性事件,對(duì)粘性事件立即進(jìn)行分發(fā)
        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 {
                // 如果當(dāng)前粘性事件集合中存在此事件類對(duì)應(yīng)的粘性事件對(duì)象皇耗,則進(jìn)入事件分發(fā)流程
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

其主要邏輯如下:

  1. 如果當(dāng)前訂閱信息沒有注冊(cè)過南窗,則按照訂閱類型和優(yōu)先級(jí)將訂閱信息的封裝類Subscription加入到訂閱信息集合subscriptionsByEventType中(subscriptionsByEventType以事件類型為key,以訂閱信息列表為value的訂閱信息集合)郎楼。
  2. 將事件類型加入到訂閱事件類型集合typesBySubscriber(typesBySubscriber 以訂閱者對(duì)象為key万伤,以訂閱事件類型為value的訂閱類型信息集合)。
  3. 如果當(dāng)前訂閱的為粘性事件呜袁,則進(jìn)入事件分發(fā)的流程敌买。
    Map<Class<?>, Object> stickyEvents; 以事件類為key,以事件對(duì)象為value的粘性事件集合

方法中的Subscription是訂閱信息類阶界,封裝了訂閱者對(duì)象虹钮,訂閱方法,是否處于激活狀態(tài)等信息膘融,源碼如下:

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)

    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的注冊(cè)流程就分析完了,總結(jié)如下:


EventBus的注冊(cè)流程圖

第三步:注冊(cè)流程結(jié)束后氧映,發(fā)送消息并執(zhí)行訂閱方法

繼續(xù)來講解EventBus的事件分發(fā)春畔,即post一個(gè)事件之后怎么傳達(dá)到對(duì)應(yīng)的訂閱者的。發(fā)送消息的方式有兩種岛都,一種為發(fā)送普通消息post(Object event)律姨,一種為發(fā)送粘性消息postSticky(Object event),先來看看發(fā)送普通消息post(Object event)方法的源碼:

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
    @Override
    protected PostingThreadState initialValue() {
        return new PostingThreadState();
    }
};
/** Posts the given event to the event bus. */
public void post(Object event) {
    //currentPostingThreadState是一個(gè)ThreadLocal臼疫,他的特點(diǎn)是獲取當(dāng)前線程一份獨(dú)有的變量數(shù)據(jù)择份,不受其他線程影響。
    PostingThreadState postingState = currentPostingThreadState.get();
    //postingState就是獲取到的線程獨(dú)有的變量數(shù)據(jù) 
    List<Object> eventQueue = postingState.eventQueue;
    //把post的事件添加到事件隊(duì)列
    eventQueue.add(event);
    // 如果沒有處在事件發(fā)布狀態(tài)多矮,那么開始發(fā)送事件并一直保持發(fā)布狀態(tài)
    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;
        }
    }
}

/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
    //事件隊(duì)列
    final List<Object> eventQueue = new ArrayList<Object>();
    boolean isPosting;
    boolean isMainThread;
    Subscription subscription;
    Object event;
    boolean canceled;
}

可見post方法的大致流程為 :

  1. 首先根據(jù) currentPostingThreadState 獲取當(dāng)前線程狀態(tài) postingState 缓淹。currentPostingThreadState 其實(shí)就是一個(gè) ThreadLocal 類的對(duì)象哈打,不同的線程根據(jù)自己獨(dú)有的索引值可以得到相應(yīng)屬于自己的 postingState 數(shù)據(jù)。
  2. 然后把事件 event 加入到 eventQueue 隊(duì)列中排隊(duì)讯壶。
  3. 循環(huán)遍歷 eventQueue 料仗,取出事件發(fā)送事件。

發(fā)送單個(gè)事件是調(diào)用 postSingleEvent(Object event, PostingThreadState postingState) 方法伏蚊。其方法源碼:

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    // 得到事件的類型
    Class<?> eventClass = event.getClass();
    // 是否找到訂閱者
    boolean subscriptionFound = false;
    // 如果支持事件繼承立轧,默認(rèn)為支持
    if (eventInheritance) {
        // 查找 eventClass 的所有父類和接口
        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 {
        // 1 發(fā)送事件
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    }
    // 如果沒有訂閱者
    if (!subscriptionFound) {
        if (logNoSubscriberMessages) {
            Log.d(TAG, "No subscribers registered for event " + eventClass);
        }
        if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) {
            // 發(fā)送 NoSubscriberEvent 事件氛改,可以自定義接收
            post(new NoSubscriberEvent(this, event));
        }
    }
}

在postSingleEvent方法中,事件發(fā)送邏輯根據(jù) eventInheritance分成兩種比伏,大致流程為:
第一種:eventInheritance 默認(rèn)為true胜卤,支持事件繼承:得到 eventClass 的所有父類和接口,然后循環(huán)依次發(fā)送事件赁项;
第二種:eventInheritance 為false,不支持事件繼承:直接發(fā)送eventClass 事件葛躏。
若找不到訂閱者,默認(rèn)會(huì)發(fā)送 NoSubscriberEvent 事件悠菜。開發(fā)者可以自定義訂閱方法接收這個(gè)事件舰攒。
關(guān)于事件發(fā)送的具體操作由注釋1處可知需進(jìn)一步到 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 {
                // 發(fā)送事件
                postToSubscription(subscription, event, postingState.isMainThread);
                // 是否被取消了
                aborted = postingState.canceled;
            } finally {
                postingState.event = null;
                postingState.subscription = null;
                postingState.canceled = false;
            }
            // 如果被取消,則跳出循環(huán)
            if (aborted) {
                break;
            }
        }
        return true;
    }
    return false;
}

postSingleEventForEventType方法主要做的事情:

  • 從訂閱者注冊(cè)列表中取出eventClass事件對(duì)應(yīng)的訂閱者Subscription列表悔醋,
  • 遍歷了訂閱者Subscription摩窃,然后依次調(diào)用 postToSubscription 方法發(fā)送事件。
    postToSubscription(subscription, event, postingState.isMainThread)源碼如下:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    // 根據(jù)不同的線程模式執(zhí)行對(duì)應(yīng)
    switch (subscription.subscriberMethod.threadMode) {
        case POSTING: // 和發(fā)送事件處于同一個(gè)線程
            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: // 和發(fā)送事件處于不同的線程
            asyncPoster.enqueue(subscription, event);
            break;
        default: // 拋出異常
            throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
    }
}

void invokeSubscriber(Subscription subscription, Object event) {
    try {
        // 通過反射執(zhí)行訂閱方法
        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維護(hù)的3個(gè)線程模型變量mainThreadPoster芬骄、
backgroundPoster猾愿、asyncPoster,我們知道在使用EventBus時(shí)德玫,我們?cè)谑褂聾Subscribe注解訂閱方法時(shí)也可以指定threadMode匪蟀,代表訂閱方法所運(yùn)行的線程;指定sticky宰僧,代表是否是粘性事件材彪;指定priority,代表優(yōu)先級(jí)琴儿。其中threadMode有五種模式:

  • (POSTING)同一個(gè)線程:表示訂閱方法所處的線程和發(fā)布事件的線程是同一個(gè)線程段化。
  • (MAIN)主線程:如果發(fā)布事件的線程是主線程則直接執(zhí)行,若不是主線程需回調(diào)到主線程執(zhí)行
  • (MAIN_ORDERED)主線程順序執(zhí)行:訂閱者在主線程中調(diào)用造成。但和 MAIN 模式不同的显熏,是本模式的消息會(huì)直接進(jìn)入屬于主線程的消息隊(duì)列中排隊(duì)等待執(zhí)行,而不是阻塞主線程直接運(yùn)行晒屎。
  • (BACKGROUND)子線程:如果發(fā)布事件的線程是主線程喘蟆,那么創(chuàng)建子線程執(zhí)行缓升;否則直接執(zhí)行;
  • (ASYNC)異步線程:無論發(fā)布事件執(zhí)行在主線程還是子線程蕴轨,都利用一個(gè)子線程來執(zhí)行訂閱方法港谊。
    這四種設(shè)置的實(shí)現(xiàn)原理就在上面這出代碼里,前面也說過了其中mainThreadPoster橙弱、
    backgroundPoster歧寺、asyncPoster三個(gè)線程模型是實(shí)現(xiàn)這4中模式的關(guān)鍵。根據(jù)我們對(duì)四種模式的理解和源碼邏輯不難看出棘脐,invokeSubscriber(subscription, event)方法的作用應(yīng)該就是在當(dāng)前線程調(diào)用訂閱方法斜筐,而其中的mainThreadPoster.enqueue(subscription, event)作用應(yīng)該是回到到主線程然后調(diào)用訂閱方法,backgroundPoster.enqueue(subscription, event)和asyncPoster.enqueue(subscription, event)作用應(yīng)該都是啟動(dòng)子線程調(diào)用訂閱方法≈欤現(xiàn)在我來分別分析一下這三個(gè)線程模型的源碼顷链,先來看mainThreadPoster,跟蹤其源碼至初始化代碼處為:
ainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;

根據(jù)前面的分析知android環(huán)境下mainThreadSupport!=null,那么來看mainThreadSupport.createPoster(this) 方法源碼:

public interface MainThreadSupport {

    boolean isMainThread();

    Poster createPoster(EventBus eventBus);

    class AndroidHandlerMainThreadSupport implements MainThreadSupport {
        
        private final Looper looper;

        public AndroidHandlerMainThreadSupport(Looper looper) {
            this.looper = looper;
        }

        @Override
        public boolean isMainThread() {
            return looper == Looper.myLooper();
        }

        @Override
        public Poster createPoster(EventBus eventBus) {
            return new HandlerPoster(eventBus, looper, 10);
        }
    }

}

可見mainThreadPoster其實(shí)為HandlerPoster對(duì)象該對(duì)象持有主線程的 looper對(duì)象内斯。在分析HandlerPoster類之前我先來說明幾個(gè)概念便于講解HandlerPoster類的原理

Poster接口
發(fā)送事件是一個(gè)具體的行為蕴潦,為此EventBus抽象出來一個(gè)Poster接口出來像啼;其源碼如下:

interface Poster {
   //由于發(fā)送事件有先后順序俘闯,這里定義了一個(gè)enqueue方法
  //subscription:事件接收者
  //event:具體的事件
   void enqueue(Subscription subscription, Object event);
}

PendingPost
PendingPost為EventBus 中一個(gè)重要的類,其源碼如下:

final class PendingPost {
    private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();

    Object event;
    Subscription subscription;
    PendingPost next;

    private PendingPost(Object event, Subscription subscription) {
        this.event = event;
        this.subscription = subscription;
    }
    
    static PendingPost obtainPendingPost(Subscription subscription, Object event) {
       //從pendingPostPool獲取一個(gè)PendingPost
       synchronized (pendingPostPool) {
            int size = pendingPostPool.size();
            if (size > 0) {
                //從集合末尾獲取一個(gè)
                PendingPost pendingPost = pendingPostPool.remove(size - 1);
                pendingPost.event = event;
                pendingPost.subscription = subscription;
                pendingPost.next = null;
                return pendingPost;
            }
        }
        //如果pendingPostPool沒有忽冻,則創(chuàng)建一個(gè)
        return new PendingPost(event, subscription);
    }
    //釋放PendingPost對(duì)象真朗,其實(shí)為保留PendingPost對(duì)象,僅僅將其變量置null僧诚,類似倒了水的空瓶以備下次復(fù)用
    static void releasePendingPost(PendingPost pendingPost) {
        pendingPost.event = null;
        pendingPost.subscription = null;
        pendingPost.next = null;
        synchronized (pendingPostPool) {
            // Don't let the pool grow indefinitely
            if (pendingPostPool.size() < 10000) {
                //將pendingPost對(duì)象放入pendingPost池中遮婶,便于之后復(fù)用
                pendingPostPool.add(pendingPost);
            }
        }
    }

}

通過該類的成員變量可以看出PendingPost除了封裝了事件對(duì)象event,事件接收者對(duì)象Subscription之外,還弄了個(gè)next引用湖笨,說明其希望構(gòu)建一個(gè)鏈表結(jié)構(gòu)releasePendingPost旗扑。而pendingPostPool為PendingPost對(duì)象池用于保存PendingPost對(duì)象。其結(jié)合obtainPendingPost(Subscription subscription, Object event) 與releasePendingPost(PendingPost pendingPost) 方法實(shí)現(xiàn)PendingPost實(shí)例的復(fù)用線程池慈省。首先所以我們來看看EventBus是怎么構(gòu)建這個(gè)PendingPost鏈表的臀防,具體的構(gòu)建過程在PendingPostQueue類里面,先看看這個(gè)類的源碼:

PendingPostQueue

final class PendingPostQueue {
    //鏈表頭部引用
    private PendingPost head;
    //鏈表尾部引用
    private PendingPost tail;

    synchronized void enqueue(PendingPost pendingPost) {
        if (pendingPost == null) {
            throw new NullPointerException("null cannot be enqueued");
        }
        if (tail != null) {
            tail.next = pendingPost;
            tail = pendingPost;
        } else if (head == null) {
            //第一次執(zhí)行是走這個(gè)分支
            head = tail = pendingPost;
        } else {
            throw new IllegalStateException("Head present, but no tail");
        }
        //喚醒等待的線程
        notifyAll();
    }

    synchronized PendingPost poll() {
        PendingPost pendingPost = head;
        if (head != null) {
            head = head.next;
            if (head == null) {
                tail = null;
            }
        }
        return pendingPost;
    }

    synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
        if (head == null) {
            wait(maxMillisToWait);
        }
        return poll();
    }

}

該類也算是EventBus的核心類之一边败,在AsyncPoster,BackgroundPost,HandlerPoster里都有用到袱衷,該類的作用就是構(gòu)建具有head和tail引用的PendingPost鏈表結(jié)構(gòu)。具體的構(gòu)建行為在PendingPostQueue對(duì)象的enqueue方法里面笑窜,而其取出表頭對(duì)象的邏輯在poll()方法里面致燥,其構(gòu)建了一個(gè)先進(jìn)先出隊(duì)列。

現(xiàn)在再回到HandlerPoster類的源碼中就容易理解多了:

public class HandlerPoster extends Handler implements Poster {
    //維護(hù)PendingPost的隊(duì)列
    private final PendingPostQueue queue;
    //handler中最長處理message的時(shí)間
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    //handler活躍狀態(tài)標(biāo)志
    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) {
         //獲取一個(gè)PendingPost對(duì)象
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            //將PendingPost入隊(duì)到PendingPostQueue隊(duì)列中
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                //如果handler處于非活躍狀態(tài)則是其活躍起來
                handlerActive = true;
                //發(fā)送Message消息
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            //執(zhí)行開始計(jì)時(shí)
            long started = SystemClock.uptimeMillis();
            //不斷循環(huán)遍歷PendingPostQueue中的PendingPost對(duì)象并處理直到隊(duì)列為null
            while (true) {
                //取出一個(gè)PendingPost對(duì)象
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        //雙重檢查加鎖后再次獲取PendingPost對(duì)象
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            //如果取出的PendingPost對(duì)象仍然為null排截,則將handler設(shè)置為非活躍狀態(tài)
                            handlerActive = false;
                            return;
                        }
                    }
                }
                //如果取出的PendingPost對(duì)象不為空則請(qǐng)求其封裝的訂閱方法
                eventBus.invokeSubscriber(pendingPost);
                //如果在規(guī)定的時(shí)間內(nèi)還沒有處理完畢嫌蚤,則重新回調(diào)handleMessage處理
                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;
        }
    }
}

可見HandlerPoster 為Handler子類辐益,其又持有主線程的looper對(duì)象,所以它可通過hander機(jī)制與主線程進(jìn)行通信脱吱。在postToSubscription(Subscription subscription, Object event, boolean isMainThread) 方法中如果threadMode為MAIN類型荷腊,但當(dāng)前線程在子線程時(shí)會(huì)去調(diào)用mainThreadPoster.enqueue(subscription, event)方法,即HandlerPoster的enqueue(subscription, event)方法急凰,其會(huì)將subscription, event封裝成PendingPost對(duì)象并入隊(duì)到維護(hù)的PendingPostQueue變量中女仰,并發(fā)送Message消息觸發(fā)UI線程去執(zhí)行其定義的handleMessage(Message msg) 方法,方法中會(huì)不斷循環(huán)獲取鏈表中的PendingPost抡锈,調(diào)用PendingPost中封裝的訂閱方法谐腰,當(dāng)鏈表中的事件處理完畢后退出while循環(huán)读串。或者是在規(guī)定的時(shí)間內(nèi)maxMillisInsideHandleMessage沒有將事件處理完,則繼續(xù)調(diào)用sendMessage装获。繼而重新回調(diào)handleMessage方法,事件會(huì)繼續(xù)執(zhí)行柔袁。(這是為了避免隊(duì)列過長或者事件耗時(shí)較長時(shí)孝宗,while循環(huán)阻塞主線程造成卡頓。算是個(gè)小技巧四瘫。)從而達(dá)到通過handler通信機(jī)制完成訂閱方法在主線程執(zhí)行的任務(wù)汉嗽。
接著再來分析一下BackgroundPoster ,其源碼如下:

final class BackgroundPoster implements Runnable, Poster {
    //維護(hù)PendingPost的隊(duì)列
    private final PendingPostQueue queue;
    private final EventBus eventBus;
    //線程池是否在運(yùn)行的標(biāo)志
    private volatile boolean executorRunning;

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

    public void enqueue(Subscription subscription, Object event) {
        //獲取一個(gè)PendingPost對(duì)象
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            //將PendingPost入隊(duì)到PendingPostQueue隊(duì)列中
            queue.enqueue(pendingPost);
            if (!executorRunning) {
                如果線程池未在運(yùn)行狀態(tài)則使其運(yùn)行
                executorRunning = true; 
                eventBus.getExecutorService().execute(this);
            }
        }
    }

    @Override
    public void run() {
        try {
            try {
                //不斷循環(huán)遍歷PendingPostQueue中的PendingPost對(duì)象并處理直到隊(duì)列為null
                while (true) {
                    //1找蜜、從連表中獲取一個(gè)PendingPost饼暑,鏈表為null則等待一秒
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            //雙重檢查加鎖后再次獲取PendingPost對(duì)象
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                //如果還為null,認(rèn)定此時(shí)沒有事件產(chǎn)生
                                executorRunning = false;
                                //退出run方法
                                return;
                            }
                        }
                    }
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

}

可見BackgroundPoster類的代碼邏輯與HandlerPoster大同小異洗做,只是BackgroundPoster實(shí)現(xiàn)了Runnable方法并在postToSubscription(Subscription subscription, Object event, boolean isMainThread) 方法中調(diào)用backgroundPoster.enqueue(subscription, event)方法后其會(huì)把自身交于EventBus自身維護(hù)的線程池ExecutorService去子線程中執(zhí)行弓叛,即執(zhí)行其實(shí)現(xiàn)的run()方法。其run()方法邏輯與HandlerPoster的handleMessage(Message msg) 邏輯相似诚纸,需要額外注意的是撰筷,在while循環(huán)中,其先調(diào)用poll(1000)方法畦徘,如果事件鏈表為null毕籽,則wait(1000),等待事件產(chǎn)生;而后再次在用poll()獲取旧烧,如果此時(shí)仍然為null影钉,則EventBus認(rèn)為現(xiàn)階段沒有事件,則run方法執(zhí)行結(jié)束掘剪,直到下次事件來臨后繼續(xù)調(diào)用eventBus.getExecutorService().execute(this)執(zhí)行平委。還需要注意的是因?yàn)樵趂un方法中循環(huán)便利事件鏈表,所以為了防止事件阻塞夺谁,在使用ThreadModel.BACKGROUND的時(shí)候廉赔,要求此@Subricebe 方法不要執(zhí)行耗時(shí)的邏輯肉微。那么耗時(shí)的邏輯應(yīng)該在哪兒執(zhí)行呢?這就用到了ThreadModel.ASYNC模式蜡塌,其實(shí)現(xiàn)依賴AsyncPoster類碉纳,由于AsyncPoster類與BackgroundPoster類內(nèi)容除了實(shí)現(xiàn)的run()方法外其他內(nèi)容相同,這里就只貼出核心的不同部分:

 //AsyncPoster的run方法
  public void run() {
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }

可見其邏輯很簡(jiǎn)單就是獲取鏈表中的一個(gè)事件馏艾,執(zhí)行之劳曹;而不像BackGround那樣循環(huán)整個(gè)事件鏈表挨個(gè)執(zhí)行之。也因此不會(huì)導(dǎo)致事件阻塞琅摩。

分析道這里我們已經(jīng)弄清楚了EventBus是如何控制訂閱方法在哪個(gè)線程執(zhí)行的了铁孵,其中在執(zhí)行invokeSubscriber(pendingPost)方法源碼中

void invokeSubscriber(PendingPost pendingPost) {
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        //前面說的PendingPost通過空瓶回收實(shí)現(xiàn)的PendingPost復(fù)用池
        PendingPost.releasePendingPost(pendingPost);
        if (subscription.active) {
            invokeSubscriber(subscription, event);
        }
    }

可以知道,不管使用哪種ThreadMode,其最終都會(huì)去調(diào)用invokeSubscriber(subscription, event)方法通過反射的方式調(diào)用訂閱方法房资,源碼如下:

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的Post和執(zhí)行訂閱方法邏輯就分析完了,總結(jié)如下:


EventBus的Post和執(zhí)行訂閱方法邏輯

那EventBus發(fā)送粘性事件的邏輯是怎樣的呢轰异?一般情況岖沛,我們使用 EventBus 都是準(zhǔn)備好訂閱事件的方法,然后注冊(cè)事件搭独,最后在發(fā)送事件婴削,即要先有事件的接收者。但粘性事件卻恰恰相反戳稽,我們可以先發(fā)送事件馆蠕,后續(xù)再準(zhǔn)備訂閱事件的方法、注冊(cè)事件惊奇。

由于這種差異,我們分析粘性事件原理時(shí)播赁,先從事件發(fā)送開始颂郎,發(fā)送一個(gè)粘性事件通過如下方式:

EventBus.getDefault().postSticky("Hello World!");

來看postSticky()方法是如何實(shí)現(xiàn)的:

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

postSticky()方法主要做了兩件事,先將事件類型和對(duì)應(yīng)事件保存到stickyEvents中容为,方便后續(xù)使用乓序;然后執(zhí)行post(event)繼續(xù)發(fā)送事件,這個(gè)post()方法就是之前發(fā)送的post()方法坎背。所以替劈,如果在發(fā)送粘性事件前,已經(jīng)有了對(duì)應(yīng)類型事件的訂閱者得滤,及時(shí)它是非粘性的陨献,依然可以接收到發(fā)送出的粘性事件。

發(fā)送完粘性事件后懂更,再準(zhǔn)備訂閱粘性事件的方法眨业,并完成注冊(cè)急膀。核心的注冊(cè)事件流程還是我們之前的register()方法中的subscribe()方法,前邊分析subscribe()方法時(shí)龄捡,有一段沒有分析的代碼卓嫂,就是用來處理粘性事件的:

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        ......
        ......
        ......
        // 如果當(dāng)前訂閱事件的方法的Subscribe注解的sticky屬性為true,即該方法可接受粘性事件
        if (subscriberMethod.sticky) {
            // 默認(rèn)為true聘殖,表示是否向上查找事件的父類
            if (eventInheritance) {
                // stickyEvents就是發(fā)送粘性事件時(shí)晨雳,保存了事件類型和對(duì)應(yīng)事件
                Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry<Class<?>, Object> entry : entries) {
                    Class<?> candidateEventType = entry.getKey();
                    // 如果candidateEventType是eventType的子類或
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        // 獲得對(duì)應(yīng)的事件
                        Object stickyEvent = entry.getValue();
                        // 處理粘性事件
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

可以看到,處理粘性事件就是在 EventBus 注冊(cè)時(shí)奸腺,遍歷stickyEvents悍募,如果當(dāng)前要注冊(cè)的事件訂閱方法是粘性的,并且該方法接收的事件類型和stickyEvents中某個(gè)事件類型相同或者是其父類洋机,則取出stickyEvents中對(duì)應(yīng)事件類型的具體事件坠宴,做進(jìn)一步處理。繼續(xù)看checkPostStickyEventToSubscription()處理方法:

private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        if (stickyEvent != null) {
            postToSubscription(newSubscription, stickyEvent, isMainThread());
        }
    }

最終還是通過postToSubscription()方法完成粘性事件的處理绷旗,這就是粘性事件的整個(gè)處理流程喜鼓。

第四步:解除注冊(cè)訂閱

當(dāng)我們不在需要訂閱EventBus發(fā)送的時(shí)間時(shí),我們可以通過EventBus的unregister(Object subscriber)方法解除訂閱衔肢,其源碼如下:

public synchronized void unregister(Object subscriber) {
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); // 獲取訂閱對(duì)象的所有訂閱事件類列表
        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());
        }
    }

private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); // 獲取事件類的所有訂閱信息列表庄岖,將訂閱信息從訂閱信息集合中移除,同時(shí)將訂閱信息中的active屬性置為FALSE
        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; // 將訂閱信息激活狀態(tài)置為FALSE
                    subscriptions.remove(i); // 將訂閱信息從集合中移除
                    i--;
                    size--;
                }
            }
        }
    }

可見解除注冊(cè)訂閱的流程為:

  1. 將訂閱者的訂閱信息從訂閱信息集合中移除角骤,同時(shí)將訂閱信息激活狀態(tài)置為FALSE
  2. 將訂閱者信息從訂閱者訂閱類型集合中移除
    解除注冊(cè)訂閱的流程圖如下:


    解除注冊(cè)訂閱的流程

至此我們對(duì)EventBus源碼的邏輯和實(shí)現(xiàn)原理就分析完了隅忿。

補(bǔ)充

Subscriber Index

EventBus默認(rèn)的實(shí)現(xiàn)是運(yùn)行時(shí)通過反射來查找訂閱事件的方法進(jìn)行注冊(cè),如果項(xiàng)目中有大量的訂閱事件的方法邦尊,必然會(huì)對(duì)項(xiàng)目運(yùn)行時(shí)的性能產(chǎn)生影響背桐。所以EventBus3.0以后。增加了EventBusAnnotationProcessor新特性用以優(yōu)化其性能蝉揍,其可以在編譯期讀取@Subscribe()注解并且解析其中所包含的信息生成一個(gè)輔助的索引類Subscriber Index來代替運(yùn)行時(shí)通過反射查找注解方法導(dǎo)致的性能下降的問題链峭,下面就來說說這種方式下實(shí)現(xiàn)邏輯。

使用Subscriber Index的前提

訂閱者和訂閱事件類必須是Public的又沾,訂閱者方法才能被索引到弊仪;另外,由于Java注解機(jī)制自身的限制杖刷,在匿名類中的@Subscribe注解是不能被識(shí)別的励饵,從而不能生成索引。

假如訂閱方法不滿足這個(gè)前提也這不會(huì)造成致命問題滑燃,因?yàn)樵谥坝嗛喿?cè)過程中存在這樣的邏輯:如果使用不了索引役听,那么程序?qū)⒆詣?dòng)使用反射機(jī)制。雖然這又回到了運(yùn)行時(shí)期做事情的老路上,使得性能下降禾嫉,但EventBus依然可以正常工作灾杰。

使用Subscriber Index需要的配置

Android Gradle 插件2.2.0之前,我們使用android-apt的方式熙参,在編譯期生成Subscriber Index類艳吠。所謂APT,即Annotation Processing Tool孽椰,其結(jié)合EventBus提供的EventBusAnnotationProcessor昭娩,就可以就在編譯期,對(duì)源代碼文件進(jìn)行檢測(cè)黍匾,找出其中的Annotation栏渺,從而生成目標(biāo)文件,即Subscriber Index類锐涯。
然而磕诊,畢竟android-apt是第三方插件,自Android Gradle 插件2.2.0 之后纹腌,其官方提供了相同的能力霎终,即annotationProcessor ,來完全代替 android-apt升薯,配置起來更簡(jiǎn)單莱褒,推薦大家使用。
方式一:使用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"
    }
}

其中com.monster.android.wild.MyEventBusIndex就是我們想要生成的Subscriber Index類涎劈。
方式二:使用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'
}   

同上广凸,com.monster.android.wild.MyEventBusIndex就是我們想要生成的Subscriber Index類≈朊叮可以看到谅海,這樣配置起來更簡(jiǎn)單。
在build.gradle中配置完畢之后坤候,再進(jìn)行編譯胁赢,Subscriber Index類MyEventBusIndex就會(huì)自動(dòng)為我們生成了,見下圖工程目錄中。

我們的工程中需要有使用EventBus相關(guān)的代碼才能生成Subscriber Index類白筹。

工程目錄

Subscriber Index類MyEventBusIndex是如何生成的
<meta charset="utf-8">

首先,我們需要明確谅摄,MyEventBusIndex是在編譯時(shí)期徒河,通過第三方提供的android-apt或者Gradle本身提供的annotationProcessor,結(jié)合EventBus提供的EventBusAnnotationProcessor送漠,共同協(xié)作而生成的顽照。而EventBusAnnotationProcessor由EventBus提供,也就說明具體生成邏輯是由EventBus控制,這算是經(jīng)典的模板模式代兵。
下面尼酿,我們大致看一下EventBusAnnotationProcessor是如何定義生成邏輯并生成目標(biāo)Java類文件的。大家可以從EventBus 的Github上面看到完整源代碼植影,這里只是簡(jiǎn)要的闡述:

@SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe")
@SupportedOptions(value = {"eventBusIndex", "verbose"})
public class EventBusAnnotationProcessor extends AbstractProcessor {

    // process()是該類的核心函數(shù)裳擎,就是在這里,實(shí)現(xiàn)收集和評(píng)估注解的代碼思币,以及生成Java文件
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
    // 保存訂閱者的訂閱方法信息
    private final ListMap<TypeElement, ExecutableElement> methodsByClass = new ListMap<>();
    // 保存需要跳過的訂閱者
    private final Set<TypeElement> classesToSkip = new HashSet<>();
    
        try {
            // 從build.gradle中讀取到arguments鹿响,即com.monster.android.wild.MyEventBusIndex
            String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX);
            // 收集,填充methodsByClass 
            collectSubscribers(annotations, env, messager);
            // 評(píng)估谷饿,填充classesToSkip 
            checkForSubscribersToSkip(messager, indexPackage);

            if (!methodsByClass.isEmpty()) {
                // 生成java文件(根據(jù)methodsByClass和classesToSkip)
                createInfoIndexFile(index);
            } else {
            }
        } catch (RuntimeException e) {
        }
        return true;
    }
}

    // 生成java文件惶我,其中有一部分是hardcode
    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) {
        } finally {
        }
    }

接下來我們看看生成的Subscriber Index類MyEventBusIndex

/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;

    static {
        //用來保存當(dāng)前注冊(cè)類的 Class 類型和其中事件訂閱方法的信息。
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();

        // 從以上createInfoIndexFile()的實(shí)現(xiàn)來看博投,除了類名MyEventBusIndex绸贡,只有這一段代碼是非hardcode。
        // 以訂閱者類為單位毅哗,將該訂閱者類中的所有訂閱函數(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;
        }
    }
}

接著酥艳,我們想使用生成的Subscriber Index類,就可以在構(gòu)造EventBus時(shí)爬骤,如下這樣

EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();

但如果每次都這樣寫一大串充石,未免有些繁瑣。既然我們引入了Subscriber Index霞玄,我們當(dāng)然希望我們的工程中全部使用這樣方式骤铃,這時(shí),就可以這樣

// 只設(shè)置一次坷剧,并且要在我們第一次使用EventBus之前進(jìn)行設(shè)置
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// 這樣每次獲取到默認(rèn)實(shí)例惰爬,都是使用Subscriber Index的了,代碼得到了精簡(jiǎn)惫企。
EventBus eventBus = EventBus.getDefault();

接下來分析下使用 Subscriber Index 時(shí) EventBus 的注冊(cè)流程撕瞧,我們先分析:

EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();

首先創(chuàng)建一個(gè)EventBusBuilder陵叽,然后通過addIndex()方法添加索引類的實(shí)例:

public EventBusBuilder addIndex(SubscriberInfoIndex index) {
        if (subscriberInfoIndexes == null) {
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }

即把生成的索引類MyEventBusIndex的實(shí)例保存在subscriberInfoIndexes集合中,然后用installDefaultEventBus()創(chuàng)建默認(rèn)的 EventBus實(shí)例:

public EventBus installDefaultEventBus() {
        synchronized (EventBus.class) {
            if (EventBus.defaultInstance != null) {
                throw new EventBusException("Default instance already exists." +
                        " It may be only set once before it's used the first time to ensure consistent behavior.");
            }
            EventBus.defaultInstance = build();
            return EventBus.defaultInstance;
        }
    }
public EventBus build() {
        // this 代表當(dāng)前EventBusBuilder對(duì)象
        return new EventBus(this);
    }

即用當(dāng)前EventBusBuilder對(duì)象創(chuàng)建一個(gè) EventBus 實(shí)例丛版,這樣我們通過EventBusBuilder配置的 Subscriber Index 也就傳遞到了EventBus實(shí)例中巩掺,然后賦值給EventBus的 defaultInstance成員變量。之前我們?cè)诜治?EventBus 的getDefault()方法時(shí)已經(jīng)見到了defaultInstance:

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

所以在 Application 中生成了 EventBus 的默認(rèn)單例页畦,這樣就保證了在項(xiàng)目其它地方執(zhí)行EventBus.getDefault()就能得到唯一的 EventBus 實(shí)例胖替!之前在分析注冊(cè)流程時(shí)有一個(gè)
方法findUsingInfo():

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        // 通過FindState對(duì)象來存儲(chǔ)找到的方法信息
        FindState findState = prepareFindState();
        // 初始化FindState
        findState.initForSubscriber(subscriberClass);
        // 從當(dāng)前類開始循環(huán)遍歷該類的所有父類
        while (findState.clazz != null) {
            // 1 如果我們通過EventBusBuilder配置了MyEventBusIndex,便會(huì)通過getSubscriberInfo(findState)方法獲取到subscriberInfo 寇漫,通常情況下我們使用EventBus時(shí)并沒有配置
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {
                // 如果使用了MyEventBusIndex刊殉,將會(huì)進(jìn)入到這里并獲取訂閱方法信息
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                // 未使用MyEventBusIndex將會(huì)進(jìn)入這里使用反射獲取訂閱方法信息
                findUsingReflectionInSingleClass(findState);
            }
            // 將findState.clazz設(shè)置為當(dāng)前的findState.clazz的父類
            findState.moveToSuperclass();
        }
        //返回查找到的所有訂閱信息并釋放FindState對(duì)象
        return getMethodsAndRelease(findState);
    }

當(dāng)我們使用了MyEventBusIndex時(shí)再來看看注釋1處的邏輯,getSubscriberInfo(findState)的源碼如下:

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;
            }
        }
        // 該條件成立
        if (subscriberInfoIndexes != null) {
            // 遍歷索引類實(shí)例集合
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                // 根據(jù)注冊(cè)類的 Class 類查找SubscriberInfo
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

其中subscriberInfoIndexes就是在前邊addIndex()方法中創(chuàng)建的保存了項(xiàng)目中索引類MyEventBusIndex的實(shí)例
州胳,遍歷并調(diào)用MyEventBusIndex類對(duì)象的getSubscriberInfo()方法便得到了封裝了訂閱方法信息的SubscriberInfo對(duì)象记焊。至此,代碼邏輯就捋順了~~~
總結(jié)
到這里栓撞,如何生成Subscriber Index類以及如何使用Subscriber Index類就分析完畢了遍膜。分析過程中,大家應(yīng)該就可以看到了瓤湘,核心思想就是把運(yùn)行時(shí)所需要做的耗時(shí)操作轉(zhuǎn)移到了編譯時(shí)期去做瓢颅,從而提高了整體性能。

參考文章
http://www.reibang.com/p/e9fc6484bd9d
http://www.reibang.com/p/d9516884dbd4

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末弛说,一起剝皮案震驚了整個(gè)濱河市挽懦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌木人,老刑警劉巖信柿,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異醒第,居然都是意外死亡渔嚷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門稠曼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來形病,“玉大人,你說我怎么就攤上這事霞幅∧牵” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵司恳,是天一觀的道長侥猩。 經(jīng)常有香客問我,道長抵赢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮铅鲤,結(jié)果婚禮上划提,老公的妹妹穿的比我還像新娘。我一直安慰自己邢享,他們只是感情好鹏往,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骇塘,像睡著了一般伊履。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上款违,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天唐瀑,我揣著相機(jī)與錄音,去河邊找鬼插爹。 笑死哄辣,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赠尾。 我是一名探鬼主播力穗,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼气嫁!你這毒婦竟也來了当窗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤寸宵,失蹤者是張志新(化名)和其女友劉穎崖面,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體邓馒,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嘶朱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了光酣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疏遏。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖救军,靈堂內(nèi)的尸體忽然破棺而出财异,到底是詐尸還是另有隱情,我是刑警寧澤唱遭,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布戳寸,位于F島的核電站,受9級(jí)特大地震影響拷泽,放射性物質(zhì)發(fā)生泄漏疫鹊。R本人自食惡果不足惜袖瞻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拆吆。 院中可真熱鬧聋迎,春花似錦、人聲如沸枣耀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捞奕。三九已至牺堰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颅围,已是汗流浹背伟葫。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谷浅,地道東北人扒俯。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像一疯,于是被迫代替她去往敵國和親撼玄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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