EventBus使用與源碼解析

使用篇

1.添加依賴庫(kù)
 compile 'org.greenrobot:eventbus:3.0.0'
2.注冊(cè)遂黍、訂閱、取消訂閱事件
EventBus.getDefault().register(obj);//注冊(cè)
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)//sticky:true為黏性事件堂鲜,false為一般事件
public void onMessageReceive(Object obj) {//訂閱
       //onMessageReceive這個(gè)方法名可以任意取羹应,obj為發(fā)布者發(fā)布的事件類型
       //省略...
   }
EventBus.getDefault().unregister(obj);//取消訂閱
3.事件發(fā)布者發(fā)布事件
EventBus.getDefault().post(obj);//一般事件
EventBus.getDefault().postSticky(obj);//黏性事件
4.混淆
-keepattributes *Annotation*
-keepclassmembers class **{
    @org.greenrobot.eventbus.Suscribe<methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode{*;}
#only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent{
    <init>(java.lang.Throwable);
}

源碼解析篇

當(dāng)我們使用EventBus時(shí)丘逸,首先會(huì)調(diào)用EventBus.getDefault()來獲取EventBus實(shí)例浦徊,下面看getDefault方法:
EventBus#getDefault

    static volatile EventBus defaultInstance;//EventBus實(shí)例
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

很明顯馏予,這是采用DCL雙重檢查的單例設(shè)計(jì)模式,下面看它的構(gòu)造方法:

//EventBus的建造者模式builder,通過它為EventBus設(shè)置各種默認(rèn)屬性
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
public EventBus() {
        this(DEFAULT_BUILDER);//DEFAULT_BUILDER為EventBus的建造者模式builder
    }
EventBus(EventBusBuilder builder) {
        //private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
        //訂閱者與訂閱事件的集合盔性,注意:一個(gè)訂閱者可以訂閱多個(gè)訂閱事件
        //因此是一個(gè)訂閱者和若干個(gè)訂閱事件
        subscriptionsByEventType = new HashMap<>();
        //private final Map<Object, List<Class<?>>> typesBySubscriber;
        //訂閱事件類型霞丧,根據(jù)訂閱對(duì)象輕松找到訂閱者類,用于取消訂閱時(shí)
        typesBySubscriber = new HashMap<>();
        //private final Map<Class<?>, Object> stickyEvents;
        //訂閱者和訂閱事件冕香,黏性事件
        stickyEvents = new ConcurrentHashMap<>();
        //這是一個(gè)handler,用于排隊(duì)發(fā)布事件與取出發(fā)布事件來消費(fèi)
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        //后臺(tái)線程
        backgroundPoster = new BackgroundPoster(this);
        //異步線程
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        //private final SubscriberMethodFinder subscriberMethodFinder;
        //訂閱者方法的查找類蛹尝,這個(gè)類很重要,用于查找訂閱者的訂閱方法(集合)
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        //省略...
    }

通過構(gòu)造方法悉尾,它調(diào)用了this(DEFAULT_BUILDER)突那,這里的DEFAULT_BUILDER就是EventBusBuilder,可以看出构眯,它通過建造者模式對(duì)EventBus進(jìn)行各種配置愕难。這里就不貼EventBusBuilder的代碼了,可自行閱讀EventBusBuilder源碼惫霸。
在獲取了EventBus實(shí)例后猫缭,會(huì)調(diào)用注冊(cè)方法,把訂閱者注冊(cè)到EventBus中壹店。下面看這個(gè)注冊(cè)方法:
EventBus#register

public void register(Object subscriber) {
        //獲取訂閱者類class
        Class<?> subscriberClass = subscriber.getClass();
        //通過訂閱者方法查找類的查找方法猜丹,返回訂閱方法SubscriberMethod集合
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {//遍歷訂閱方法集合
                subscribe(subscriber, subscriberMethod);//對(duì)每個(gè)訂閱者進(jìn)行注冊(cè)
            }
        }
    }

通過閱讀register源碼,我們不難看出它整體思路通過訂閱者class茫打,獲取該訂閱者里面所有的訂閱方法居触,然后開啟同步鎖并遍歷訂閱方法妖混,對(duì)每一個(gè)訂閱方法進(jìn)行注冊(cè)操作老赤。
這里要補(bǔ)充說明一下SubscriberMethod(訂閱方法)里面的幾個(gè)屬性:

public class SubscriberMethod {
    final Method method;//訂閱者定義的方法
    //ThreadMode為枚舉類型,取值如下:POSTING,MAIN,BACKGROUND,ASYNC
    final ThreadMode threadMode;//訂閱方法工作的線程
    final Class<?> eventType;//EventBus發(fā)布(post)的事件類型制市,即訂閱方法接收的數(shù)據(jù)類型
    final int priority;//訂閱方法優(yōu)先級(jí)
    final boolean sticky;//是否為黏性方法
    //其余部分省略...
}

下面看看訂閱者方法查找類究竟是如何查找訂閱方法的领追?
SubscriberMethodFinder#findSubscriberMethods

//METHOD_CACHE是緩存雌澄,key是訂閱者,value是訂閱方法集合
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
//是否忽略注解器生成的XxxEventBus
private final boolean ignoreGeneratedIndex;
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        //從緩存中獲取訂閱者類class的訂閱方法
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {//一旦在緩存中找到,就不再查找掘托,直接返回訂閱方法集合
            return subscriberMethods;
        }
        //ignoreGeneratedIndex默認(rèn)為false,也可以通過EventBusBuilder來設(shè)置。
        //這里因?yàn)槲覀兪峭ㄟ^EventBus.getDefault()方法來獲取的實(shí)例
        //所以ignoreGeneratedIndex是默認(rèn)false的情況,即執(zhí)行else情況
        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        if (subscriberMethods.isEmpty()) {//如果在訂閱者中沒有找到訂閱方法悉患,則拋未找到異常
            throw new EventBusException("Subscriber " + subscriberClass
                    + " and its super classes have no public methods with the @Subscribe annotation");
        } else {
            //把訂閱者類class與訂閱方法集合存入緩存肩钠,方便下次調(diào)用不再繼續(xù)查找,直接緩存讀取
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

閱讀上面源碼可知:首先從緩存METHOD_CACHE中查找訂閱方法集合兽间,找到立即返回历葛,后面不會(huì)再執(zhí)行;否則嘀略,根據(jù)ignoreGeneratedIndex是否為true,執(zhí)行查找獲取對(duì)應(yīng)的訂閱方法集合恤溶;接著對(duì)找到的訂閱方法集合判空乓诽,如果是空,則拋出異常咒程,不為空時(shí)鸠天,則把訂閱者與對(duì)應(yīng)的訂閱方法集合存入緩存,方便下次調(diào)用不需重新查找帐姻,最后返回訂閱方法集合稠集。
從上面源碼可知,查找訂閱方法由findUsingInfo方法執(zhí)行卖宠,下面看該方法:
SubscriberMethodFinder#findUsingInfo

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();//返回FindState實(shí)例
        findState.initForSubscriber(subscriberClass);//初始化FindState
        while (findState.clazz != null) {//當(dāng)findState.clazz == null時(shí)結(jié)束循環(huán)
            //獲取訂閱者信息巍杈,并賦值給findState.subscriberInfo
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {//對(duì)findState.subscriberInfo進(jìn)行判空
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

觀察findUsingInfo方法,首先執(zhí)行的是prepareFindState方法扛伍,返回查找狀態(tài)類FindState的實(shí)例筷畦。
這里需補(bǔ)充一下說明FindState,它是SubscriberMethodFinder的靜態(tài)內(nèi)部類:
SubscriberMethodFinder靜態(tài)內(nèi)部類FindState

static class FindState {
        //訂閱方法
        final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
        final Map<Class, Object> anyMethodByEventType = new HashMap<>();
        final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
        final StringBuilder methodKeyBuilder = new StringBuilder(128);

        Class<?> subscriberClass;//訂閱者class
        Class<?> clazz;//訂閱者class
        boolean skipSuperClasses;//是否跳過檢查父類class
        SubscriberInfo subscriberInfo;//訂閱者信息
        //其他略...
}

下面看prepareFindState方法是如何返回查找狀態(tài)類FindState實(shí)例的:
SubscriberMethodFinder#prepareFindState

private static final int POOL_SIZE = 4;
//定義一個(gè)容量為4的查找狀態(tài)數(shù)組
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
private FindState prepareFindState() {
        synchronized (FIND_STATE_POOL) {//以數(shù)組作為同步鎖
            for (int i = 0; i < POOL_SIZE; i++) {//對(duì)數(shù)組進(jìn)行遍歷
                FindState state = FIND_STATE_POOL[i];
                if (state != null) {//一旦發(fā)現(xiàn)查找狀態(tài)不為空刺洒,立即返回鳖宾,并把數(shù)組內(nèi)查找狀態(tài)置為空
                    FIND_STATE_POOL[i] = null;
                    return state;
                }
            }
        }
        return new FindState();//在數(shù)組內(nèi)的查找狀態(tài)均為空時(shí),新建一個(gè)查找狀態(tài)實(shí)例返回
    }

在獲得FindState實(shí)例后逆航,調(diào)用initForSubscriber初始化該狀態(tài):
FindState#initForSubscriber

void initForSubscriber(Class<?> subscriberClass) {
     this.subscriberClass = clazz = subscriberClass;//把訂閱者class賦值給subscriberClass和clazz
     skipSuperClasses = false;
     subscriberInfo = null;
}

之后在findState.clazz不為空的條件下循環(huán)鼎文,直到findState.clazz為空結(jié)束循環(huán),并通過調(diào)用getMethodsAndRelease方法返回List<SubscriberMethod>因俐。
先看循環(huán)體內(nèi)邏輯拇惋,調(diào)用getSubscriberInfo方法,返回查找狀態(tài)的訂閱者信息findState.subscriberInfo抹剩,依據(jù)該信息是否為空撑帖,執(zhí)行相應(yīng)的操作。還是看看getSubscriberInfo方法:
SubscriberMethodFinder#getSubscriberInfo

private List<SubscriberInfoIndex> subscriberInfoIndexes;
private SubscriberInfo getSubscriberInfo(FindState findState) {
        //通過FindState#initForSubscriber方法 => subscriberInfo = null可知澳眷,不會(huì)執(zhí)行if語句塊
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }
        //subscriberInfoIndexes到目前為止胡嘿,均未被賦值,因此也是null钳踊,因此也不會(huì)執(zhí)行if語句塊
        if (subscriberInfoIndexes != null) {
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;//有上面可知衷敌,最終執(zhí)行返回null
    }

該方法,首先是判空:在傳入的查找狀態(tài)findState中存儲(chǔ)的訂閱信息不為空且其父類定閱信息不為空的條件下拓瞪,獲取其父類訂閱信息superclassInfo缴罗,然后在傳入的訂閱信息與其父類訂閱信息一致的情況下,返回該父類訂閱信息祭埂;第二次判空:當(dāng)subscriberInfoIndexes不為空時(shí)面氓,對(duì)數(shù)組subscriberInfoIndexes進(jìn)行遍歷,在訂閱者信息不為空時(shí)返回,不在往下執(zhí)行侧但;在兩次判空均為null時(shí)矢空,直接返回null(訂閱者信息)。
對(duì)于getSubscriberInfo方法禀横,首先傳入的findState就是上面通過初始化之后的狀態(tài)屁药,即findState.subscriberInfo為空,接著由EventBus的構(gòu)造方法subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex)可知柏锄,subscriberInfoIndexes也是空酿箭,所以最終返回的訂閱者信息是空,所以findUsingInfo方法的循環(huán)體里面的判斷語句執(zhí)行else語句:findUsingReflectionInSingleClass(findState)趾娃。
SubscriberMethodFinder#findUsingReflectionInSingleClass

private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            //通過反射獲取訂閱者所有方法(public + private)
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            //通過反射獲取訂閱者所有方法(public)
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
        for (Method method : methods) {//遍歷所有的方法
            int modifiers = method.getModifiers();//獲取方法的修飾符
            //只有方法修飾符是public且不是abstract或static才能進(jìn)入執(zhí)行if語句塊
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                //獲取方法的參數(shù)類型數(shù)組
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {//只有當(dāng)方法的參數(shù)為一個(gè)時(shí)缭嫡,才能執(zhí)行if語句塊
                    //滿足上面所有條件的方法獲取方法注解@Subscribe
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {//當(dāng)獲取的注解不是空時(shí),此方法才是訂閱者類的訂閱方法
                        //獲取方法參數(shù)類型抬闷,即post(Object event)的event類型
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {//當(dāng)訂閱者與訂閱方添加成功后
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            //把訂閱方法添加到findState.subscriberMethods里面
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                //默認(rèn)情況下strictMethodVerification=false妇蛀,因此if語句塊不會(huì)執(zhí)行。
                } 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);
                }
            //默認(rèn)情況下strictMethodVerification=false笤成,因此if語句塊不會(huì)執(zhí)行评架。
            } 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");
            }
        }
    }

通過閱讀findUsingReflectionInSingleClass源碼,我們知道:首先通過反射獲取訂閱者類的所有方法炕泳,然后對(duì)方法進(jìn)行遍歷纵诞,只有當(dāng)方法修飾符為public、方法參數(shù)只有一個(gè)且該方法存在@Subscribe注解時(shí)培遵,該方法才是訂閱者類的訂閱方法浙芙,接著獲取@Subscribe注解實(shí)例(不為空時(shí)),把訂閱方法(包括方法籽腕,訂閱者嗡呼,線程模式,優(yōu)先級(jí)节仿,是否黏性事件)添加到findState.subscriberMethods里面晤锥。
分析完findUsingReflectionInSingleClass源碼掉蔬,接著就是findState.moveToSuperclass:
FindState#moveToSuperclass

void moveToSuperclass() {
            if (skipSuperClasses) {//跳過父類方法檢測(cè)
                clazz = null;
            } else {//檢測(cè)父類方法時(shí)
                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;
                }
            }
        }

從這段源碼可知:當(dāng)skipSuperClasses為true廊宪,或者父類方法是系統(tǒng)方法時(shí),置clazz為null女轿,其他時(shí)候置clazz為clazz.getSuperclass()箭启。
最后就是跳出循環(huán)體,通過調(diào)用getMethodsAndRelease方法蛉迹,返回訂閱方法集合了傅寡。
SubscriberMethodFinder#getMethodsAndRelease

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
        List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
        findState.recycle();
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                if (FIND_STATE_POOL[i] == null) {
                    FIND_STATE_POOL[i] = findState;
                    break;
                }
            }
        }
        return subscriberMethods;
    }

這一段源碼很簡(jiǎn)單,就是通過findState.subscriberMethods新建一個(gè)訂閱者方法集合并最終返回,接著重置findState荐操,并把之前的findState設(shè)置到FIND_STATE_POOL數(shù)組中芜抒。
分析完查找訂閱者的訂閱方法之后,回到EventBus的register方法托启,采用同步鎖并遍歷訂閱方法集合宅倒,對(duì)找到的每一個(gè)訂閱方法與訂閱者進(jìn)行注冊(cè)操作。
EventBus#subscribe

    // Must be called in synchronized block必須在同步代碼塊中調(diào)用
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        //首先獲取EventBus的post數(shù)據(jù)類型
        Class<?> eventType = subscriberMethod.eventType;
        //創(chuàng)建一個(gè)訂閱事件(包括訂閱者和訂閱方法)
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        //Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
        //以發(fā)布的數(shù)據(jù)類型為key屯耸,獲取線程安全的發(fā)布事件集合
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {//當(dāng)集合為空時(shí)拐迁,new一個(gè),并把發(fā)布數(shù)據(jù)類型與發(fā)布事件存入緩存
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {//當(dāng)集合不為空疗绣,且集合內(nèi)包含該發(fā)布事件线召,則拋異常。
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }
        //這部分代碼是把訂閱事件按優(yōu)先級(jí)插入集合或集合末尾插入
        int size = subscriptions.size();
        for (int i = 0; i <= size; i++) {
            //當(dāng)?shù)竭_(dá)集合末尾或此發(fā)布事件的優(yōu)先級(jí)高于前一個(gè)多矮,則在末尾或該一事件前插入缓淹,之后跳出循環(huán)
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        //Map<Object, List<Class<?>>> typesBySubscriber
        //從緩存中根據(jù)key(訂閱者)取出value(發(fā)布事件類型)
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {//如果集合為空,創(chuàng)建一個(gè)
            subscribedEvents = new ArrayList<>();
            //把訂閱者與發(fā)布的訂閱事件集合存入緩存
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);//把發(fā)布的訂閱事件存入集合

        if (subscriberMethod.sticky) {//根據(jù)是否黏性事件
            if (eventInheritance) {//默認(rèn)是true塔逃,事件是否有繼承性
                // 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 {
                //Map<Class<?>, Object> stickyEvents
                //緩存中根據(jù)發(fā)布的事件類型class,取出原發(fā)布事件
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

剖析該方法前割卖,先補(bǔ)充說明一下訂閱事件Subscription這個(gè)類:

final class Subscription {
    final Object subscriber;//訂閱者類
    final SubscriberMethod subscriberMethod;//訂閱方法(方法,線程患雏,發(fā)布事件類型鹏溯,優(yōu)先級(jí),黏性等)
    //一旦EventBus#unregister被調(diào)用淹仑,active就會(huì)變成false丙挽,
    //這將通過隊(duì)列事件傳遞EventBus#invokeSubscriber來檢查,以防止競(jìng)態(tài)條件匀借。
    volatile boolean active;
}

了解完訂閱事件Subscription后颜阐,再閱讀subscribe方法源碼:首先是根據(jù)訂閱方法,獲取發(fā)布數(shù)據(jù)類型class吓肋,接著創(chuàng)建訂閱事件凳怨,根據(jù)訂閱事件集合是否為空,空則創(chuàng)建集合是鬼,并把發(fā)布數(shù)據(jù)class與訂閱事件集合存入緩存肤舞;不為空則拋重復(fù)注冊(cè)異常;接著根據(jù)訂閱事件的優(yōu)先級(jí)或是否到達(dá)末尾均蜜,把訂閱事件插入適當(dāng)?shù)奈恢美钇剩蝗缓蟾鶕?jù)發(fā)布數(shù)據(jù)class集合是否為空,空則創(chuàng)建囤耳,并把訂閱者與發(fā)布事件集合存入緩存篙顺,不為空時(shí)偶芍,把發(fā)布的事件存入發(fā)布事件集合。最后根據(jù)是否為黏性事件完成事件注冊(cè)德玫。
下面看checkPostStickyEventToSubscription方法:
EventBus#checkPostStickyEventToSubscription

private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        if (stickyEvent != null) {//stickyEvent必不為空
            postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
        }
    }

//根據(jù)訂閱事件的線程模式執(zhí)行不同的方法匪蟀,第三個(gè)參數(shù)是判斷是否為主線程
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING://在哪個(gè)線程post就在哪個(gè)線程接收事件并處理
                invokeSubscriber(subscription, event);//反射調(diào)用method方法
                break;
            case MAIN://僅在主線程接收處理
                if (isMainThread) {
                    invokeSubscriber(subscription, event);//反射調(diào)用method方法
                } else {
                    mainThreadPoster.enqueue(subscription, event);//handler處理
                }
                break;
            case BACKGROUND://僅在后臺(tái)程接收處理
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);//線程池處理
                } else {
                    invokeSubscriber(subscription, event);//反射調(diào)用method方法
                }
                break;
            case ASYNC://另啟線程(workthread)接收處理
                asyncPoster.enqueue(subscription, event);//線程池處理
                break;
            default://不屬于以上線程,直接拋未知線程異常
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }

至此宰僧,EventBus的register方法分析完畢,下面看post方法:
EventBus#post

public void post(Object event) {
        //獲取發(fā)送線程的實(shí)例postingState
        PostingThreadState postingState = currentPostingThreadState.get();
        //獲取派送事件隊(duì)列,并把事件加入隊(duì)列
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {//事件未派送狀態(tài)
            //判斷是否UI線程
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            postingState.isPosting = true;//事件派送狀態(tài)標(biāo)志位置為true
            if (postingState.canceled) {//正在派送狀態(tài),如果被取消,拋內(nèi)部異常
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                while (!eventQueue.isEmpty()) {
                    //當(dāng)派送事件隊(duì)列不為空時(shí),對(duì)第一個(gè)事件進(jìn)行派送,并移除該事件
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {//最終都會(huì)把是否在派送標(biāo)志位和UI線程標(biāo)志位置為false
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }
//ThreadLocal可保證不同線程值多樣性(線程獨(dú)享),這里僅創(chuàng)建了一個(gè)PostingThreadState實(shí)例
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };
//字面理解:發(fā)送線程的狀態(tài)
//eventbus備注*For ThreadLocal, much faster to set (and get multiple values)*
final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<Object>();//事件隊(duì)列
        boolean isPosting;//標(biāo)志位,是否在派送
        boolean isMainThread;//標(biāo)志位,是否主線程
        Subscription subscription;//訂閱事件處理器:訂閱者+訂閱方法+是否激活標(biāo)志位
        Object event;//事件
        boolean canceled;//標(biāo)志位,是否被取消
    }

post方法很簡(jiǎn)單,大體思路:首先獲取派送事件狀態(tài),然后把要派送的是按放入該派送事件狀態(tài)的事件隊(duì)列中,根據(jù)標(biāo)志位未派送狀態(tài),對(duì)事件隊(duì)列中的事件逐一取出并進(jìn)行派送,并且最終把標(biāo)志位是否被派送和UI線程置為false,下面看postSingleEvent方法是如何進(jìn)行事件派送的:
EventBus#postSingleEvent

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;//默認(rèn)訂閱處理器未發(fā)現(xiàn)處理方法
        //默認(rèn)為true,表示訂閱事件具有繼承性,即該事件的父類或與該事件實(shí)現(xiàn)同一接口的訂閱者都會(huì)處理該事件
        if (eventInheritance) {
            //查找所有可處理該事件相關(guān)類或接口
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {//遍歷所有事件派送到的類
                Class<?> clazz = eventTypes.get(h);
                //檢查這些可處理事件的類是否有處理對(duì)應(yīng)事件的方法,返回值為boolean類型
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {//未發(fā)現(xiàn)可處理該派送事件的類(即沒有訂閱者)
            if (logNoSubscriberMessages) {
                Log.d(TAG, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }
//查找所有事件類
private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
        //private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
        synchronized (eventTypesCache) {//同步鎖
            List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
            if (eventTypes == null) {
                eventTypes = new ArrayList<>();
                Class<?> clazz = eventClass;
                //直到clazz為空跳出循環(huán)
                while (clazz != null) {//查找派送事件的所有父類以及實(shí)現(xiàn)同一接口的類
                    eventTypes.add(clazz);
                    addInterfaces(eventTypes, clazz.getInterfaces());
                    clazz = clazz.getSuperclass();
                }
                //使用緩存把派送事件類型及其父類或?qū)崿F(xiàn)同一接口類進(jìn)行緩存
                eventTypesCache.put(eventClass, eventTypes);
            }
            return eventTypes;
        }
    }
//檢查所有可處理該派送事件的類
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {//根據(jù)相關(guān)List<?>取值subscriptions
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        //如果訂閱事件處理器不為空,且有值時(shí),進(jìn)行遍歷,否則返回false
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;//標(biāo)志位,未被強(qiáng)制停止
                try {
                    //發(fā)送到訂閱處理
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {//最終釋放派送事件,訂閱時(shí)間處理器以及標(biāo)志位是否被取消
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {//如果被取消,則跳出循環(huán),返回false
                    break;
                }
            }
            return true;
        }
        return false;
    }

postSingleEvent方法首先根據(jù)發(fā)布的事件event來獲取該發(fā)布事件的class,然后根據(jù)發(fā)布事件具有繼承性,查找所有可消費(fèi)處理該事件的相關(guān)類(訂閱者)來處理該事件,過程中又回到前面已經(jīng)分析過的postToSubscription方法,根據(jù)不同線程,調(diào)用不同方法對(duì)事件進(jìn)行派發(fā).至此,post方法也分析完畢.
EventBus#postSticky

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

補(bǔ)充說明下黏性事件,因?yàn)轲ば允录鋵?shí)也是調(diào)用post方法,只是在post之前先緩存了黏性事件而已.
最后分析一下反注冊(cè)u(píng)nregister方法
EventBus#unregister

public synchronized void unregister(Object subscriber) {
        //private final Map<Object, List<Class<?>>> typesBySubscriber;
        //從集合中取出該訂閱者所有的訂閱事件
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {//如果訂閱事件集合不為空時(shí)
            for (Class<?> eventType : subscribedTypes) {//遍歷,反注冊(cè)
                unsubscribeByEventType(subscriber, eventType);
            }
            //從集合中移除該訂閱者
            typesBySubscriber.remove(subscriber);
        } else {//為空時(shí)不需要反注冊(cè)
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }
//解除訂閱者與訂閱事件之間的關(guān)系
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        //private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
        //從集合中取出所有關(guān)于該訂閱者的訂閱事件處理器
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {//當(dāng)該處理器不為空時(shí)
            int size = subscriptions.size();
            for (int i = 0; i < size; i++) {//遍歷
                Subscription subscription = subscriptions.get(i);
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;//標(biāo)志位置為false
                    subscriptions.remove(i);//移除訂閱事件處理器
                    i--;
                    size--;
                }
            }
        }
    }

反注冊(cè)的邏輯也是很簡(jiǎn)單:首先根據(jù)訂閱者從集合中取出該訂閱者的所有訂閱事件,然后在該訂閱事件不為空時(shí),進(jìn)行遍歷,并逐一進(jìn)行解除.
OK,至此,EventBus源碼分析完結(jié)!
T.T~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末萄窜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子撒桨,更是在濱河造成了極大的恐慌查刻,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凤类,死亡現(xiàn)場(chǎng)離奇詭異穗泵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)谜疤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門佃延,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人夷磕,你說我怎么就攤上這事履肃。” “怎么了坐桩?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵尺棋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我绵跷,道長(zhǎng)膘螟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任碾局,我火速辦了婚禮荆残,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘净当。我一直安慰自己内斯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布像啼。 她就那樣靜靜地躺著俘闯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪埋合。 梳的紋絲不亂的頭發(fā)上备徐,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天萄传,我揣著相機(jī)與錄音甚颂,去河邊找鬼蜜猾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛振诬,可吹牛的內(nèi)容都是我干的蹭睡。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼赶么,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼肩豁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起辫呻,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤清钥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后放闺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祟昭,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年怖侦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了篡悟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡匾寝,死狀恐怖搬葬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情艳悔,我是刑警寧澤急凰,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站猜年,受9級(jí)特大地震影響香府,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜码倦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一企孩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧袁稽,春花似錦勿璃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至歹撒,卻和暖如春莲组,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背暖夭。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工锹杈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撵孤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓竭望,卻偏偏與公主長(zhǎng)得像邪码,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子咬清,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345