EventBus源码解析

前言:作为一名Android开发人员,EventBus这个开源库想必大家在日常的开发工作中都有用到吧。有关EventBus的介绍,在这里就略过了。如果你还不了解的话,参照EventBus官方文档。记得我第一次接触到EventBus的时候,就被它的强大深深折服了,很好奇它内部是怎么工作的。这两天翻看了下源码,做下学习笔记,希望也能帮助到大家。在这里我选取的EventBus版本为3.1.1,也就是当前的最新版本。

我们知道,在EventBus中,如果我们想要订阅事件的话,首先我们必须要注册成为订阅者:

    protected void onResume() {
        super.onResume();
        EventBus.getDefault().register(this);
    }

我们点进去EventBus的getDefault()方法看一下:

  public EventBus() {
        this(DEFAULT_BUILDER);       //EventBus对象在创建的时候使用了建造者模式
    }

接着跟进去:

EventBus(EventBusBuilder builder) {
        logger = builder.getLogger();

        //1.subscriptionsByEventType 是一个hashmap,以事件类型为key,以订阅者事件集合为value,代表的是事件类型与其订阅者事件之间的对应关系。
        //每个事件类型,可能对应多个订阅者事件,所以value值为订阅者事件集合。
        subscriptionsByEventType = new HashMap<>();

        //2.typesBySubscriber 是一个hashmap,以订阅者为key,以事件类型集合为value,代表的是订阅者与其下事件类型之间的对应关系。
        //每个订阅者可能会对应多个事件类型,所以value值为事件类型集合。
        typesBySubscriber = new HashMap<>();

        //3.粘性事件
        stickyEvents = new ConcurrentHashMap<>();

        mainThreadSupport = builder.getMainThreadSupport();

        //4.mainThreadPoster 切换至主线程时使用
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;

        //5.backgroundPoster 切换至后台线程时使用
        backgroundPoster = new BackgroundPoster(this);

        //6.独立开辟新线程时使用
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        eventInheritance = builder.eventInheritance;
        executorService = builder.executorService;
    }

EventBus的主要部分就是我在上述代码中标注的六点。大家可以先理解下。

EventBus的getDefault方法就被我们分析完了,我们了解了EventBus对象的创建过程。接下来就开始解刨register方法了。我们照例跟进去:

 public void register(Object subscriber) {
         // 1
        Class<?> subscriberClass = subscriber.getClass();  

        // 2      
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);   

        // 3  
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

我们通常会在Activity或者Fragment的onResume方法中完成订阅操作,将当前Activity对象或者Fragment对象作为参数传入。那么这个时候当前Activity对象或者Fragment对象就作为了订阅者。

首先在 1 处获得当前订阅者对应的Class对象,然后调用了SubscriberMethodFinder的findSubscriberMethods方法,将Class对象作为参数传入,来获取到当前订阅者对应的所有订阅方法。最后将订阅方法集合进行遍历操作,分别对每个订阅方法完成“订阅”。

接下来我们跟进去SubscriberMethodFinder(订阅者方法找寻器)的findSubscriberMethods方法去看一下,看下它是怎么获取到当前订阅者对应的所有订阅方法的。

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {

        // 1
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
  
        // 2
        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            subscriberMethods = findUsingInfo(subscriberClass);
        }

       // 3
        if (subscriberMethods.isEmpty()) {
            throw new EventBusException("Subscriber " + subscriberClass
                    + " and its super classes have no public methods with the @Subscribe annotation");
        } else {
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

我先简单介绍下,METHOD_CACHE为一个HashMap,以订阅者对应的Class对象为key,以订阅方法集合为value,用作订阅方法的缓存。在 1 处首先从METHOD_CACHE中获取当前订阅者对应的订阅方法集合,如果返回的订阅方法列表不为null,则直接返回订阅方法列表。因为我们是首次订阅,所以subscriberMethods 为null,程序接着往下走。 2 处的ignoreGeneratedIndex在EventBus实现中默认为false,会走到else语句,通过findUsingInfo方法来获取当前订阅者对应的订阅方法集合。 3 处会判断当前订阅者对应的订阅方法集合是否为空,如果为空,会直接抛出异常。如果订阅方法集合不为空,则将订阅者Class对象与对应的订阅方法集合存储到METHOD_CACHE缓存中。

下面我们针对 3 处抛出的异常做个验证。怎么样才会让EventBus抛出这个异常呢?根据我们刚才的分析,那就是使当前订阅者对应的订阅方法集合为空。怎么着才会使它为空呢?很简单,我们在一个Activity中只参与订阅而没有对应的事件接收方法:

在这里我以MainActivity为例,只在它的onResume方法中完成了订阅操作,而在MainActivity没有任何事件接收方法。(当然你在onDestroy方法中取不取消订阅都没有影响)MainActivity代码如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onResume() {
        super.onResume();
        EventBus.getDefault().register(this);
    }
}

这个时候我们运行下我们的程序:

Caused by: org.greenrobot.eventbus.EventBusException: Subscriber class com.example.administrator.eventbustest.MainActivity and its super classes have no public methods with the @Subscribe annotation
                                                       at org.greenrobot.eventbus.SubscriberMethodFinder.findSubscriberMethods(SubscriberMethodFinder.java:67)
                                                       at org.greenrobot.eventbus.EventBus.register(EventBus.java:140)
                                                       at com.example.administrator.eventbustest.MainActivity.onResume(MainActivity.java:19)
                                                       at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1263)
                                                       at android.app.Activity.performResume(Activity.java:6160)
                                                       at android.app.Activity.performResume(Activity.java:6355)
                                                       at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3053)
                                                       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3102) 
                                                       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2463)

果然如此,app部署到手机上直接一闪而退。对比下异常信息,你会发现正是我们在 3 处抛出的异常哈哈,异常信息提示为:订阅者类MainActivity及它的所有父类都没有使用@Subscribe注解标注的public方法。我们通过这个小实验发散开来,无论是Android的FrameWork层还是第三方开源框架,是不是我们在了解了其内部源码后会对我们定位一些异常信息有帮助呢?对!绝对是有帮助的!

咳咳,我们接着我们之前的思路,定位到 2 处,具体怎么通过findUsingInfo方法来获取当前订阅者对应的订阅方法集合的呢?我们跟进去看一下:

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {

        //1. 通过调用prepareFindState方法来获取FindState对象
        FindState findState = prepareFindState();

        //2. 对findstate对象进行初始化操作
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {

                //3. 通过反射等操作获取到订阅方法
                // 将订阅方法添加到FindState的subscriberMethods集合中
                findUsingReflectionInSingleClass(findState);
            }

            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

1 处,通过调用prepareFindState方法来获取FindState对象。是怎么获取的?FindState对象又是用来做什么的呢?在这里我简单说下,FindState对象就是用来临时存储当前查找状态的。获取操作代码:

// private static final int POOL_SIZE = 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();
    }

在这里我简单说下,FIND_STATE_POOL它就是一个FindState类型数组,数组大小为4,用来作为FindState对象的缓存。

代码中从FIND_STATE_POOL的脚标为0处开始遍历操作,如果返回的FindState对象不为空,就直接将FindState对象return掉,否则调用new FindState()进行新对象创建操作。

接着看下 2 处:

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

2 处对findstate对象进行了初始化操作,将订阅者Class对象赋值给成员变量subscriberClass和clazz。

接着让我们来到 3 处,看下具体怎么操作的:

private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {

            // 1. 我们刚才对findState.clazz进行了赋值操作,也就是我们的订阅者Class对象
            //通过反射获取到该订阅者中所有声明的方法
            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;
        }

        //遍历methods方法数组
        for (Method method : methods) {
           
            // 获取方法修饰符并判断是不是PUBLIC修饰或者默认修饰符
            int modifiers = method.getModifiers();
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {

                //获得方法的参数类型,判断参数个数是否为1
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {

                    //获得方法Subscribe类型注解并判断是否为null
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {
                       
                        //获取参数类型,也就是EventBus订阅方法事件类型
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                            //获取到订阅方法所要运行的线程环境,与EventBus使用时指定的线程方式对应。
                            ThreadMode threadMode = subscribeAnnotation.threadMode();

                            //创建SubscriberMethod对象,并添加到subscriberMethods订阅者方法集合中
                            //SubscriberMethod中封装了订阅方法、事件类型、线程环境以及优先级等信息
                            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");
            }
        }
    }

我们回到findUsingInfo方法的最后一句return getMethodsAndRelease(findState);

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

getMethodsAndRelease方法所做的操作就是将刚才新创建的findState对象中存储的信息全部清空掉,然后添加到FIND_STATE_POOL缓存数组中。最后将订阅者方法集合返回。

终于又折回到最初的register方法中了:

public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

接下来我们跟进去subscribe方法,看下是怎么对每个订阅方法完成“订阅”的。

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {

        //1.获取到订阅方法对应的事件类型
        Class<?> eventType = subscriberMethod.eventType;

        //2.对当前订阅者和订阅方法进一步封装,包装成Subscription对象(订阅者事件)
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);

        //3.调用subscriptionsByEventType 的get方法,将事件类型作为key传入,获取到该事件类型对应的订阅者事件集合
        //关于 subscriptionsByEventType 在EventBus的构造方法中已经讲述过了,忘记的话可以向上翻看一下
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);

        //4. 如果该事件类型对应的订阅者事件集合为null,则会新创建一个订阅者事件集合,并以该事件类型为key,以新创建的订阅者事件集合为value,添加到subscriptionsByEventType中。
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            if (subscriptions.contains(newSubscription)) {

               //当我们在一个Activity或者Fragment中,有相同的订阅方法时(与方法名称无关),会抛出该异常。
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }

        //5. 将新创建的订阅者事件按照优先级添加到订阅者事件集合中
        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;
            }
        }

        //6. 通过typesBySubscriber的get方法,获取到当前订阅者所对应的订阅事件类型集合
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        //7. 将该事件类型添加到事件类型集合中
        subscribedEvents.add(eventType);

        //8.判断是否为粘性事件
        if (subscriberMethod.sticky) {
            // eventInheritance默认为true,只是起到优化作用,对后续调用没有影响
            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();

                        //9. 如果是粘性事件,最终会调用到此方法
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

下面我们简单看下 9 处的checkPostStickyEventToSubscription方法,源码如下:

private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        if (stickyEvent != null) {
            // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
            // --> Strange corner case, which we don't take care of here.
            postToSubscription(newSubscription, stickyEvent, isMainThread());
        }
    }

可以看到checkPostStickyEventToSubscription内部最终又是调用postToSubscription方法实现的。我们使用EventBus的post方法发送普通事件,最终也是调用到postToSubscription方法来处理的。可以简单说粘性事件就是模拟普通事件的post方法来实现的。这也就解释了粘性事件在发送之后注册仍旧可以收到的原因了。

以上就是EventBus的register方法全部实现过程。

下面我们接着看下EventBus的取消订阅方法,也就是EventBus.getDefault().unregister(this);
我们点进去unregister方法里面看下:

public synchronized void unregister(Object subscriber) {
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            typesBySubscriber.remove(subscriber);
        } else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

unregister的方法实现很简单。首先会调用typesBySubscriber的get方法,获取到当前订阅者对应的事件类型集合。然后对该事件类型集合进行判断,如果集合为null,则直接打印出警告信息,提示我们“订阅者”在此之前并没有订阅过。如果集合不为null,则会进行两部操作:第一步,遍历当前订阅者对应的事件类型集合,调用subscriptionsByEventType的get方法,获取到每个事件类型对应的订阅者事件集合,然后再对每个事件类型对应的订阅者事件集合进行遍历操作,从订阅者事件集合中将当前订阅者的订阅事件移除掉。第二步,将当前订阅者从typesBySubscriber中移除掉。
下面我贴下unsubscribeByEventType方法的源码,相信你一看就会理解了。

private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();
            for (int i = 0; i < size; i++) {
                Subscription subscription = subscriptions.get(i);
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

就这样,EventBus取消订阅的方法也就分析完毕了,有没有很简单哈哈。

接下来终于到了我们的post发送事件的方法了:
EventBus.getDefault().post(new MessageEvent("hello"));我们点进去post方法去看下:

public void post(Object event) {
        //private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>()
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

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

首先从currentPostingThreadState中获取到PostingThreadState这个对象,currentPostingThreadState是个什么东西???我在代码中已经标注过了,它就是一个ThreadLocal,关于ThreadLocal,相信看过Handler源码的同志都会熟悉,对的,简单理解下,ThreadLocal保证了线程间数据的独立性。然后将event事件添加到事件队列中,接着进入到if语句里面,标记当前线程是不是主线程。接着进入while循环,不断从事件队列头部取出事件,调用postSingleEvent方法,逐个发送事件。我们跟进去看下:

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
     
        //1. 获取到当前事件对应的事件Class
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
 
        //2.无论eventInheritance的值为true 或者 false,最终都会调用到postSingleEventForEventType方法。
        if (eventInheritance) {
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {

            //3. 调用postSingleEventForEventType方法。
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

我们跟进去postSingleEventForEventType去看下:

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                try {
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }

方法中首先会调用subscriptionsByEventType的get方法,获取到当前事件类型对应的订阅者事件集合。接下来对当前事件类型对应的订阅者事件集合进行判断,最终又会调用到postToSubscription方法中。postToSubscription方法???有没有一种似曾相识的感觉?对的,就是我们之前分析的粘性事件最后调用到的方法哈哈。

我们点进去postToSubscription方法看一下:

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC:
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }

在方法中首先对订阅者事件标注的线程进行判断,这里我们就拿MAIN线程来举例。如果订阅者事件标注的线程为MAIN,就表明我们的订阅者事件方法体想要在UI线程中执行,这个时候会判断当前线程是不是主线程,如果是主线程就直接调用invokeSubscriber方法进行操作,如果不是主线程,则通过mainThreadPoster进行线程切换咯。

我们先看下当前线程是主线程的情况,也就是会直接调用到invokeSubscriber方法。我们跟进去看下:

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

what? ? ?最终竟然还是通过反射来实现方法调用的哈哈哈哈!

如果当前线程不是主线程的时候,又进行怎么处理的呢?这里我们看到会调用mainThreadPoster的enqueue方法来将订阅者事件和event对象进行入队操作。话说mainThreadPoster是个什么鬼???

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是由MainThreadSupport来创建的,由上述代码可知,MainThreadSupport是个接口,它的的实现类为AndroidHandlerMainThreadSupport。mainThreadPoster对象也就是HandlerPoster实例对象。最终也就是调用到HandlerPoster的enqueue方法来将订阅者事件和event对象进行入队操作。在这里还要提一点,AndroidHandlerMainThreadSupport中的looper对象为主线程looper。

我们接着看下HandlerPoster的enqueue方法:

//1. public class HandlerPoster extends Handler implements Poster {

public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {

           //2. private final PendingPostQueue queue = new PendingPostQueue();
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

可以看到最终又是调用到了PendingPostQueue的enqueue方法进行入队操作。在这里我们直接看下HandlerPoster的handleMessage方法,该方法运行在主线程。

   @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }

                //1.调用eventBus的invokeSubscriber方法。
                eventBus.invokeSubscriber(pendingPost);
                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;
        }
    }

可以看到,最终调用到了eventBus的invokeSubscriber方法,而invokeSubscriber又调用到invokeSubscriber方法。同样还是通过反射来实现方法调用,只不过多了一个线程切换而已。

关于EventBus的源码就解析到这里了,笔者能力有限,有什么表达不正确的,还望各位老哥指出,如果有帮助到你们,还望点颗小心心支持下。

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

推荐阅读更多精彩内容

  • 博文出处:EventBus源码解析,欢迎大家关注我的博客,谢谢! 0001B 时近年末,但是也没闲着。最近正好在看...
    俞其荣阅读 1,254评论 1 16
  • 前言 在写这篇源码解析到一半时发现EventBus有很多高级用法是不能直接忽略的,于是回过头来写了EventBus...
    CharmingWong阅读 373评论 1 4
  • 一、注册主要流程 EventBus的注册代码如下: register方法主要做了三件事: 获取订阅者类的class...
    andcoder阅读 401评论 0 2
  • (1)eventbus的使用 为了方便分析EventBus的源码,这里我们先整个demo出来,源码如下: (2)E...
    砺雪凝霜阅读 860评论 1 4
  • EventBus是一个开源的事件总线项目,项目地址:EventBus EventBus通过注册监听器和发布消息的方...
    JasmineBen阅读 924评论 1 4