EventBus源码解析

作者: Android_Jian | 来源:发表于2018-07-20 15:38 被阅读50次

    前言:作为一名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的源码就解析到这里了,笔者能力有限,有什么表达不正确的,还望各位老哥指出,如果有帮助到你们,还望点颗小心心支持下。

    相关文章

      网友评论

        本文标题:EventBus源码解析

        本文链接:https://www.haomeiwen.com/subject/ehmxmftx.html