EventBus源码解析

作者: 雷l阵l雨 | 来源:发表于2018-03-06 23:34 被阅读105次

    EventBus的基本用法

    注册事件
    EventBus.getDefault().register(this);
    
    解除注册
    EventBus.getDefault().unregister(this);
    
    发送事件
    EventBus.getDefault().post(event);
    
    处理事件
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void XXX(Object event) {
        ...
    }
    

    注解@Subscribe

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface Subscribe {
        ThreadMode threadMode() default ThreadMode.POSTING;
    
        /**
         * If true, delivers the most recent sticky event (posted with
         * {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
         */
        boolean sticky() default false;
    
        /** Subscriber priority to influence the order of event delivery.
         * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
         * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
         * delivery among subscribers with different {@link ThreadMode}s! */
        int priority() default 0;
    }
    

    这是一个自定义的运行时注解,有三个属性,threadMode、sticky、priority。
    threadMode表示处理事件所在的线程,有POSTING、MAIN、BACKGROUND和ASYNC四种线程模型,默认为POSTING。
    sticky是否是粘性事件,默认为false。
    priority为优先级,默认值为0,值越大优先级越高。

    EventBus的getDefault()

    EventBus.getDefault()采用单例模式,创建一个EventBus对象,初始化了subscriptionsByEventType和typesBySubscriber两个HashMap,用以存储订阅者、订阅方法和订阅事件的相关信息。

    //这是一个单例模式
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    //创建了一个EventBus对象
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }
    
    public EventBus() {
        this(DEFAULT_BUILDER);
    }
    
    EventBus(EventBusBuilder builder) {
        //一个HashMap,以事件类型eventType为key,以存储了订阅者和订阅方法的集合CopyOnWriteArrayList<Subscription>为value
        subscriptionsByEventType = new HashMap<>();
        //一个HashMap,以订阅者subscriber为key,以订阅者所订阅的事件类型eventType的集合List<Class<?>>为value
        typesBySubscriber = new HashMap<>();
        //粘性事件相关的集合,这里不对粘性事件做分析,有兴趣的自行学习
        stickyEvents = new ConcurrentHashMap<>();
        //主线线程事件发送者
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        //后台线程事件发送者
        backgroundPoster = new BackgroundPoster(this);
        //异步线程事件发送者
        asyncPoster = new AsyncPoster(this);
            ...
    }
    

    注册register

    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        //获取订阅者的订阅方法的集合,后面有对findSubscriberMethods的描述
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
    
    // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
        //Subscription封装了订阅者subscriber和订阅方法subscriberMethod
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        //subscriptions若为空,先初始化,subscriptions已包含newSubscription,说明已被注册过,抛异常
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }
    
        int size = subscriptions.size();
        for (int i = 0; i <= size; i++) {
            //按优先级把newSubscription添加到subscriptions,即添加到subscriptionsByEventType
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }
    
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        //把eventType添加到subscribedEvents,即添加到typesBySubscriber
        subscribedEvents.add(eventType);
    
        //粘性事件相关处理
        if (subscriberMethod.sticky) {
            if (eventInheritance) {
                // Existing sticky events of all subclasses of eventType have to be considered.
                // Note: Iterating over all events may be inefficient with lots of sticky events,
                // thus data structure should be changed to allow a more efficient lookup
                // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
                Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry<Class<?>, Object> entry : entries) {
                    Class<?> candidateEventType = entry.getKey();
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }
    

    从上面代码可以看出,注册其实就是把当前订阅者相关的所有newSubscription存入subscriptionsByEventType,把当前订阅者订阅的所有eventType存入typesBySubscriber。

    因为newSubscription包含了订阅者subscriber和订阅方法subscriberMethod,subscriptionsByEventType的key为事件类型eventType,
    所以在subscriptionsByEventType中可以根据事件类型eventType获取所有的类型为eventType的订阅方法subscriberMethod。因为typesBySubscriber的key为订阅者subscriber,所以在typesBySubscriber中可以根据订阅者subscriber获取订阅者订阅的所有的事件类型eventType。

    subscriberMethodFinder.findSubscriberMethods(subscriberClass)

    方法findSubscriberMethods是为了获取订阅者的订阅方法的集合List<SubscriberMethod>,查看findSubscriberMethods这个方法的源码可以发现如果不使用索引,最终会调用findUsingReflectionInSingleClass方法,而默认是不使用索引的,对索引感兴趣的请自行学习,下面是findUsingReflectionInSingleClass方法的源码:

    private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // This is faster than getMethods, especially when subscribers are fat classes like Activities
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            //获取订阅者的所有方法
            // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
        for (Method method : methods) {
            int modifiers = method.getModifiers();
            //方法名前有public,没有abstract、static
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                //方法只有一个参数
                if (parameterTypes.length == 1) {
                    //方法的@Subscribe注解
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                            //获取注解中的threadMode
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            //findState.subscriberMethods是一个List<SubscriberMethod>集合,创建订阅方法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");
            }
        }
    }
    

    从上面源码中可以看出,集合findState.subscriberMethods就是我们要获取的集合,最后通过getMethodsAndRelease(FindState findState)从FindState中获取这个集合

    解除注册unregister

    /** Unregisters the given subscriber from all event classes. */
    public synchronized void unregister(Object subscriber) {
        //根据订阅者subscriber获取订阅者订阅的所有的事件类型
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                //从subscriptionsByEventType中移除订阅者对应的subscription
                unsubscribeByEventType(subscriber, eventType);
            }
            //移除订阅者订阅的所有的事件类型
            typesBySubscriber.remove(subscriber);
        } else {
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }
    
    /*
    *从subscriptionsByEventType中移除订阅者对应的subscription,subscription包含subscriberMethod,
    *所以其实是从subscriptionsByEventType中移除订阅者对应的处理eventType类型事件的方法subscriberMethod
    */
    /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
    private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        //获取所有的类型为eventType的Subscription的集合
        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);
                //判断是否是当前订阅者subscriber
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }
    

    从上面代码可以看出,解除注册其实就是从typesBySubscriber中移除订阅者订阅的所有的事件类型eventType,从subscriptionsByEventType中移除所有当前订阅者对应的处理eventType类型事件的方法subscriberMethod。

    发送事件post

    post方法最终调用的是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 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);
        }
    }
    

    从上面可以看出发送者和处理函数在相同线程直接调用invokeSubscriber,不相同时,分别调用mainThreadPoster.enqueue、backgroundPoster.enqueue和asyncPoster.enqueue。其中mainThreadPoster.enqueue是通过Handler将消息发送到主线程最终再调用invokeSubscriber,而backgroundPoster.enqueue和asyncPoster.enqueue都是通过调用线程池的线程的run方法最终调用invokeSubscriber,所以postToSubscription方法最终调的都是invokeSubscriber方法,只是所在线程不同罢了。

    从invokeSubscriber的源码可以看出,它通过反射调用处理事件的方法,方法的参数是event。

    void invokeSubscriber(Subscription subscription, Object event) {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }
    

    最后

    EventBus维护了subscriptionsByEventType和typesBySubscriber两个HashMap,其中typesBySubscriber的key为订阅者subscriber,value为订阅者订阅的所有的事件类型eventType的集合,便于注册和解除注册时添加移除当前订阅者订阅的事件类型。subscriptionsByEventType的key为eventType,value为由订阅者和处理eventType类型事件的方法subscriberMethod组成的subscription对象的集合,便于发送事件时通过事件类型eventType获取处理对应事件的方法,最后通过反射机制调用该方法。


    欢迎关注.jpg

    相关文章

      网友评论

        本文标题:EventBus源码解析

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