EventBus使用与源码解析

使用篇

1.添加依赖库
 compile 'org.greenrobot:eventbus:3.0.0'
2.注册、订阅、取消订阅事件
EventBus.getDefault().register(obj);//注册
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)//sticky:true为黏性事件,false为一般事件
public void onMessageReceive(Object obj) {//订阅
       //onMessageReceive这个方法名可以任意取,obj为发布者发布的事件类型
       //省略...
   }
EventBus.getDefault().unregister(obj);//取消订阅
3.事件发布者发布事件
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);
}

源码解析篇

当我们使用EventBus时,首先会调用EventBus.getDefault()来获取EventBus实例,下面看getDefault方法:
EventBus#getDefault

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

很明显,这是采用DCL双重检查的单例设计模式,下面看它的构造方法:

//EventBus的建造者模式builder,通过它为EventBus设置各种默认属性
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;
        //订阅者与订阅事件的集合,注意:一个订阅者可以订阅多个订阅事件
        //因此是一个订阅者和若干个订阅事件
        subscriptionsByEventType = new HashMap<>();
        //private final Map<Object, List<Class<?>>> typesBySubscriber;
        //订阅事件类型,根据订阅对象轻松找到订阅者类,用于取消订阅时
        typesBySubscriber = new HashMap<>();
        //private final Map<Class<?>, Object> stickyEvents;
        //订阅者和订阅事件,黏性事件
        stickyEvents = new ConcurrentHashMap<>();
        //这是一个handler,用于排队发布事件与取出发布事件来消费
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        //后台线程
        backgroundPoster = new BackgroundPoster(this);
        //异步线程
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        //private final SubscriberMethodFinder subscriberMethodFinder;
        //订阅者方法的查找类,这个类很重要,用于查找订阅者的订阅方法(集合)
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        //省略...
    }

通过构造方法,它调用了this(DEFAULT_BUILDER),这里的DEFAULT_BUILDER就是EventBusBuilder,可以看出,它通过建造者模式对EventBus进行各种配置。这里就不贴EventBusBuilder的代码了,可自行阅读EventBusBuilder源码。
在获取了EventBus实例后,会调用注册方法,把订阅者注册到EventBus中。下面看这个注册方法:
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);//对每个订阅者进行注册
            }
        }
    }

通过阅读register源码,我们不难看出它整体思路通过订阅者class,获取该订阅者里面所有的订阅方法,然后开启同步锁并遍历订阅方法,对每一个订阅方法进行注册操作。
这里要补充说明一下SubscriberMethod(订阅方法)里面的几个属性:

public class SubscriberMethod {
    final Method method;//订阅者定义的方法
    //ThreadMode为枚举类型,取值如下:POSTING,MAIN,BACKGROUND,ASYNC
    final ThreadMode threadMode;//订阅方法工作的线程
    final Class<?> eventType;//EventBus发布(post)的事件类型,即订阅方法接收的数据类型
    final int priority;//订阅方法优先级
    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默认为false,也可以通过EventBusBuilder来设置。
        //这里因为我们是通过EventBus.getDefault()方法来获取的实例
        //所以ignoreGeneratedIndex是默认false的情况,即执行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与订阅方法集合存入缓存,方便下次调用不再继续查找,直接缓存读取
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

阅读上面源码可知:首先从缓存METHOD_CACHE中查找订阅方法集合,找到立即返回,后面不会再执行;否则,根据ignoreGeneratedIndex是否为true,执行查找获取对应的订阅方法集合;接着对找到的订阅方法集合判空,如果是空,则抛出异常,不为空时,则把订阅者与对应的订阅方法集合存入缓存,方便下次调用不需重新查找,最后返回订阅方法集合。
从上面源码可知,查找订阅方法由findUsingInfo方法执行,下面看该方法:
SubscriberMethodFinder#findUsingInfo

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();//返回FindState实例
        findState.initForSubscriber(subscriberClass);//初始化FindState
        while (findState.clazz != null) {//当findState.clazz == null时结束循环
            //获取订阅者信息,并赋值给findState.subscriberInfo
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {//对findState.subscriberInfo进行判空
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

观察findUsingInfo方法,首先执行的是prepareFindState方法,返回查找状态类FindState的实例。
这里需补充一下说明FindState,它是SubscriberMethodFinder的静态内部类:
SubscriberMethodFinder静态内部类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方法是如何返回查找状态类FindState实例的:
SubscriberMethodFinder#prepareFindState

private static final int POOL_SIZE = 4;
//定义一个容量为4的查找状态数组
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
private FindState prepareFindState() {
        synchronized (FIND_STATE_POOL) {//以数组作为同步锁
            for (int i = 0; i < POOL_SIZE; i++) {//对数组进行遍历
                FindState state = FIND_STATE_POOL[i];
                if (state != null) {//一旦发现查找状态不为空,立即返回,并把数组内查找状态置为空
                    FIND_STATE_POOL[i] = null;
                    return state;
                }
            }
        }
        return new FindState();//在数组内的查找状态均为空时,新建一个查找状态实例返回
    }

在获得FindState实例后,调用initForSubscriber初始化该状态:
FindState#initForSubscriber

void initForSubscriber(Class<?> subscriberClass) {
     this.subscriberClass = clazz = subscriberClass;//把订阅者class赋值给subscriberClass和clazz
     skipSuperClasses = false;
     subscriberInfo = null;
}

之后在findState.clazz不为空的条件下循环,直到findState.clazz为空结束循环,并通过调用getMethodsAndRelease方法返回List<SubscriberMethod>。
先看循环体内逻辑,调用getSubscriberInfo方法,返回查找状态的订阅者信息findState.subscriberInfo,依据该信息是否为空,执行相应的操作。还是看看getSubscriberInfo方法:
SubscriberMethodFinder#getSubscriberInfo

private List<SubscriberInfoIndex> subscriberInfoIndexes;
private SubscriberInfo getSubscriberInfo(FindState findState) {
        //通过FindState#initForSubscriber方法 => subscriberInfo = null可知,不会执行if语句块
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }
        //subscriberInfoIndexes到目前为止,均未被赋值,因此也是null,因此也不会执行if语句块
        if (subscriberInfoIndexes != null) {
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;//有上面可知,最终执行返回null
    }

该方法,首先是判空:在传入的查找状态findState中存储的订阅信息不为空且其父类定阅信息不为空的条件下,获取其父类订阅信息superclassInfo,然后在传入的订阅信息与其父类订阅信息一致的情况下,返回该父类订阅信息;第二次判空:当subscriberInfoIndexes不为空时,对数组subscriberInfoIndexes进行遍历,在订阅者信息不为空时返回,不在往下执行;在两次判空均为null时,直接返回null(订阅者信息)。
对于getSubscriberInfo方法,首先传入的findState就是上面通过初始化之后的状态,即findState.subscriberInfo为空,接着由EventBus的构造方法subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex)可知,subscriberInfoIndexes也是空,所以最终返回的订阅者信息是空,所以findUsingInfo方法的循环体里面的判断语句执行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才能进入执行if语句块
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                //获取方法的参数类型数组
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {//只有当方法的参数为一个时,才能执行if语句块
                    //满足上面所有条件的方法获取方法注解@Subscribe
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {//当获取的注解不是空时,此方法才是订阅者类的订阅方法
                        //获取方法参数类型,即post(Object event)的event类型
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {//当订阅者与订阅方添加成功后
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            //把订阅方法添加到findState.subscriberMethods里面
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                //默认情况下strictMethodVerification=false,因此if语句块不会执行。
                } 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);
                }
            //默认情况下strictMethodVerification=false,因此if语句块不会执行。
            } 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源码,我们知道:首先通过反射获取订阅者类的所有方法,然后对方法进行遍历,只有当方法修饰符为public、方法参数只有一个且该方法存在@Subscribe注解时,该方法才是订阅者类的订阅方法,接着获取@Subscribe注解实例(不为空时),把订阅方法(包括方法,订阅者,线程模式,优先级,是否黏性事件)添加到findState.subscriberMethods里面。
分析完findUsingReflectionInSingleClass源码,接着就是findState.moveToSuperclass:
FindState#moveToSuperclass

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

从这段源码可知:当skipSuperClasses为true,或者父类方法是系统方法时,置clazz为null,其他时候置clazz为clazz.getSuperclass()。
最后就是跳出循环体,通过调用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;
    }

这一段源码很简单,就是通过findState.subscriberMethods新建一个订阅者方法集合并最终返回,接着重置findState,并把之前的findState设置到FIND_STATE_POOL数组中。
分析完查找订阅者的订阅方法之后,回到EventBus的register方法,采用同步锁并遍历订阅方法集合,对找到的每一个订阅方法与订阅者进行注册操作。
EventBus#subscribe

    // Must be called in synchronized block必须在同步代码块中调用
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        //首先获取EventBus的post数据类型
        Class<?> eventType = subscriberMethod.eventType;
        //创建一个订阅事件(包括订阅者和订阅方法)
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        //Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
        //以发布的数据类型为key,获取线程安全的发布事件集合
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {//当集合为空时,new一个,并把发布数据类型与发布事件存入缓存
            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;
            }
        }

        //Map<Object, List<Class<?>>> typesBySubscriber
        //从缓存中根据key(订阅者)取出value(发布事件类型)
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {//如果集合为空,创建一个
            subscribedEvents = new ArrayList<>();
            //把订阅者与发布的订阅事件集合存入缓存
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);//把发布的订阅事件存入集合

        if (subscriberMethod.sticky) {//根据是否黏性事件
            if (eventInheritance) {//默认是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
                //缓存中根据发布的事件类型class,取出原发布事件
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

剖析该方法前,先补充说明一下订阅事件Subscription这个类:

final class Subscription {
    final Object subscriber;//订阅者类
    final SubscriberMethod subscriberMethod;//订阅方法(方法,线程,发布事件类型,优先级,黏性等)
    //一旦EventBus#unregister被调用,active就会变成false,
    //这将通过队列事件传递EventBus#invokeSubscriber来检查,以防止竞态条件。
    volatile boolean active;
}

了解完订阅事件Subscription后,再阅读subscribe方法源码:首先是根据订阅方法,获取发布数据类型class,接着创建订阅事件,根据订阅事件集合是否为空,空则创建集合,并把发布数据class与订阅事件集合存入缓存;不为空则抛重复注册异常;接着根据订阅事件的优先级或是否到达末尾,把订阅事件插入适当的位置;然后根据发布数据class集合是否为空,空则创建,并把订阅者与发布事件集合存入缓存,不为空时,把发布的事件存入发布事件集合。最后根据是否为黏性事件完成事件注册。
下面看checkPostStickyEventToSubscription方法:
EventBus#checkPostStickyEventToSubscription

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

//根据订阅事件的线程模式执行不同的方法,第三个参数是判断是否为主线程
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING://在哪个线程post就在哪个线程接收事件并处理
                invokeSubscriber(subscription, event);//反射调用method方法
                break;
            case MAIN://仅在主线程接收处理
                if (isMainThread) {
                    invokeSubscriber(subscription, event);//反射调用method方法
                } else {
                    mainThreadPoster.enqueue(subscription, event);//handler处理
                }
                break;
            case BACKGROUND://仅在后台程接收处理
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);//线程池处理
                } else {
                    invokeSubscriber(subscription, event);//反射调用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) {
        //获取发送线程的实例postingState
        PostingThreadState postingState = currentPostingThreadState.get();
        //获取派送事件队列,并把事件加入队列
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {//事件未派送状态
            //判断是否UI线程
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            postingState.isPosting = true;//事件派送状态标志位置为true
            if (postingState.canceled) {//正在派送状态,如果被取消,抛内部异常
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                while (!eventQueue.isEmpty()) {
                    //当派送事件队列不为空时,对第一个事件进行派送,并移除该事件
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {//最终都会把是否在派送标志位和UI线程标志位置为false
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }
//ThreadLocal可保证不同线程值多样性(线程独享),这里仅创建了一个PostingThreadState实例
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };
//字面理解:发送线程的状态
//eventbus备注*For ThreadLocal, much faster to set (and get multiple values)*
final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<Object>();//事件队列
        boolean isPosting;//标志位,是否在派送
        boolean isMainThread;//标志位,是否主线程
        Subscription subscription;//订阅事件处理器:订阅者+订阅方法+是否激活标志位
        Object event;//事件
        boolean canceled;//标志位,是否被取消
    }

post方法很简单,大体思路:首先获取派送事件状态,然后把要派送的是按放入该派送事件状态的事件队列中,根据标志位未派送状态,对事件队列中的事件逐一取出并进行派送,并且最终把标志位是否被派送和UI线程置为false,下面看postSingleEvent方法是如何进行事件派送的:
EventBus#postSingleEvent

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;//默认订阅处理器未发现处理方法
        //默认为true,表示订阅事件具有继承性,即该事件的父类或与该事件实现同一接口的订阅者都会处理该事件
        if (eventInheritance) {
            //查找所有可处理该事件相关类或接口
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {//遍历所有事件派送到的类
                Class<?> clazz = eventTypes.get(h);
                //检查这些可处理事件的类是否有处理对应事件的方法,返回值为boolean类型
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            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) {
                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为空跳出循环
                while (clazz != null) {//查找派送事件的所有父类以及实现同一接口的类
                    eventTypes.add(clazz);
                    addInterfaces(eventTypes, clazz.getInterfaces());
                    clazz = clazz.getSuperclass();
                }
                //使用缓存把派送事件类型及其父类或实现同一接口类进行缓存
                eventTypesCache.put(eventClass, eventTypes);
            }
            return eventTypes;
        }
    }
//检查所有可处理该派送事件的类
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {//根据相关List<?>取值subscriptions
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        //如果订阅事件处理器不为空,且有值时,进行遍历,否则返回false
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;//标志位,未被强制停止
                try {
                    //发送到订阅处理
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {//最终释放派送事件,订阅时间处理器以及标志位是否被取消
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {//如果被取消,则跳出循环,返回false
                    break;
                }
            }
            return true;
        }
        return false;
    }

postSingleEvent方法首先根据发布的事件event来获取该发布事件的class,然后根据发布事件具有继承性,查找所有可消费处理该事件的相关类(订阅者)来处理该事件,过程中又回到前面已经分析过的postToSubscription方法,根据不同线程,调用不同方法对事件进行派发.至此,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);
    }

补充说明下黏性事件,因为黏性事件其实也是调用post方法,只是在post之前先缓存了黏性事件而已.
最后分析一下反注册unregister方法
EventBus#unregister

public synchronized void unregister(Object subscriber) {
        //private final Map<Object, List<Class<?>>> typesBySubscriber;
        //从集合中取出该订阅者所有的订阅事件
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {//如果订阅事件集合不为空时
            for (Class<?> eventType : subscribedTypes) {//遍历,反注册
                unsubscribeByEventType(subscriber, eventType);
            }
            //从集合中移除该订阅者
            typesBySubscriber.remove(subscriber);
        } else {//为空时不需要反注册
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }
//解除订阅者与订阅事件之间的关系
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        //private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
        //从集合中取出所有关于该订阅者的订阅事件处理器
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {//当该处理器不为空时
            int size = subscriptions.size();
            for (int i = 0; i < size; i++) {//遍历
                Subscription subscription = subscriptions.get(i);
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;//标志位置为false
                    subscriptions.remove(i);//移除订阅事件处理器
                    i--;
                    size--;
                }
            }
        }
    }

反注册的逻辑也是很简单:首先根据订阅者从集合中取出该订阅者的所有订阅事件,然后在该订阅事件不为空时,进行遍历,并逐一进行解除.
OK,至此,EventBus源码分析完结!
T.T~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339