EventBus源码解析(一)EventBus事件订阅

前言

说起Eventbus,相信不少同学都已经使用过。之前一直听别人提起,但是我一直没有使用过。前段时间在做一个IMdemo的时候用上了,原来模块间的通信可以这么方便,遂勾起了我的兴趣,决定好好研究一番。那么它的用法和好处我就不介绍了,直接进入主题。

正题

本篇文章解析EventBus注册的源码。


EventBus注册

可以看到EventBus使用的单例模式创建的实例,但是EventBus的构造函数却不是私有的(这样就可以自己new个EventBus对象),让我们看看源码。

  public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }
    /**
     * Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
     * central bus, consider {@link #getDefault()}.
     */
    public EventBus() {
        this(DEFAULT_BUILDER);
     }

    EventBus(EventBusBuilder builder) {
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        backgroundPoster = new BackgroundPoster(this);
        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使用getDefault()方法。
有些时候我们想要自己去配置一个EventBusBuilder,但是源码中没有提供可以把EventBusBuilder作为参数传递给EventBus然后创建EventBus实例的方法。那么如何创建一个我们自己定义的EventBusBuilder实例呢?这时候需要使用另一种创建EventBus实例的方法了。源码给我们提供了一个得到EventBusBuilder的方法

public static EventBusBuilder builder() {
        return new EventBusBuilder();
    }

为什么给我们提供这个方法,我们不可以直接new一个出来吗?
原来EventBusBuilder的构造函数不是public的。。。。但是EventBusBuilder有个方法可以得到EventBus实例

/**
     * Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be
     * done only once before the first usage of the default EventBus.
     *
     * @throws EventBusException if there's already a default EventBus instance in place
     */
    public EventBus installDefaultEventBus() {
        synchronized (EventBus.class) {
            if (EventBus.defaultInstance != null) {
                throw new EventBusException("Default instance already exists." +
                        " It may be only set once before it's used the first time to ensure consistent behavior.");
            }
            EventBus.defaultInstance = build();
            return EventBus.defaultInstance;
        }
    }

下面放上创建自己配制EventBusBuilder的EventBus实例完整代码

EventBus e   = EventBus.builder()
              .eventInheritance(true)
              .ignoreGeneratedIndex(true)
              .installDefaultEventBus();

接着往下走,得到了EventBus的时候后就要register。

/**
     * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
     * are no longer interested in receiving events.
     * 

* Subscribers have event handling methods that must be annotated by {@link Subscribe}. * The {@link Subscribe} annotation also allows configuration like {@link * ThreadMode} and priority. */ public void register(Object subscriber) { //得到订阅者的运行时类Class对象 Class subscriberClass = subscriber.getClass(); //订阅者中被包装成SubscriberMethod对象的接收方法的集合 List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }

源码的注释是注册订阅者接收时间,不再使用的时候通过unregister(Object)方法取消注册。注册者必须含有一个处理事件并含有Subscribe注解的方法,注释中允许配置ThreadMode等属性。
通过subscriberMethodFinder.findSubscriberMethods(subscriberClass)这个方法找到订阅中接收事件的方法并包装成SubscriberMethod对象,点进去看一下

List findSubscriberMethods(Class subscriberClass) {
        //在缓存中查找是否含有SubscriberMethod集合
        List subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
         //ignoreGeneratedIndex默认为为false
        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 {
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

首先通过缓存找到是否SubscriberMethod对象,我们第一次注册该订阅者,所有缓存中是没有的。接着判断ignoreGeneratedIndex(是否忽略生成的索引),这个可以在EventBusBuildr中去设置,默认为false。所以执行 subscriberMethods = findUsingInfo(subscriberClass)

private List findUsingInfo(Class subscriberClass) {
        FindState findState = prepareFindState();
        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 {
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }

private FindState prepareFindState() {
        //private static final int POOL_SIZE = 4;
       // private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
        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();
    }

private SubscriberInfo getSubscriberInfo(FindState findState) {
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }
        if (subscriberInfoIndexes != null) {
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

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

这里的findState.subscriberInfo为null,执行findUsingReflectionInSingleClass(findState)

private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // This is faster than getMethods, especially when subscribers are fat classes like Activities
            //通过反射获取订阅者中的所有方法的所有公用(public)方法包括其继承类的公用方法,包括它所实现接口的方法。
            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、BRIDGE、SYNTHETIC等关键字
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
               //以数组形式拿到方法中的参数
                Class[] parameterTypes = method.getParameterTypes();
                //判断数组的长度是否为1
                if (parameterTypes.length == 1) {
                   //拿到方法的注解
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {
                         //eventType是EventBus的Model类
                        Class eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            //把订阅者中接收事件的方法包装成一个SubscriberMethod对象
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
               //参数长度>1时抛出异常
                   } 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");
            }
        }
    }
   /**   双重检查
    *    1。检查是否已添加在当前订阅者中处理事件的方法
    *    2。检查接收事件的方法的声明类
    */
boolean checkAdd(Method method, Class eventType) {
            // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
            // Usually a subscriber doesn't have methods listening to the same event type.
            Object existing = anyMethodByEventType.put(eventType, method);
            if (existing == null) {
                return true;
            } else {
                if (existing instanceof Method) {
                    if (!checkAddWithMethodSignature((Method) existing, eventType)) {
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    // Put any non-Method object to "consume" the existing Method
                    anyMethodByEventType.put(eventType, this);
                }
                return checkAddWithMethodSignature(method, eventType);
            }
        }

private boolean checkAddWithMethodSignature(Method method, Class eventType) {
            methodKeyBuilder.setLength(0);
            methodKeyBuilder.append(method.getName());
            methodKeyBuilder.append('>').append(eventType.getName());

            String methodKey = methodKeyBuilder.toString();
            Class methodClass = method.getDeclaringClass();
            Class methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
            if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
                // Only add if not already found in a sub class
                return true;
            } else {
                // Revert the put, old class is further down the class hierarchy
                subscriberClassByMethodKey.put(methodKey, methodClassOld);
                return false;
            }
        }

这段代码很长,大致就是检查接收事件的方法是否符合规范(EventBus通过此规范找到接收事件的方法)之后添加进接收事件方法的集合,否则抛出异常。并且是通过反射实现的。接着检查订阅者是否还有父类,没有则跳出循环


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

跳出循环后,拿到接收事件方法的集合,并重置findState对象

private List getMethodsAndRelease(FindState findState) {
        List 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;
    }

接着遍历SubscriberMethod的集合,订阅事件

 for (SubscriberMethod subscriberMethod : subscriberMethods) {
                //subscriber订阅者。subscriberMethod接收事件的方法
                subscribe(subscriber, subscriberMethod);
            }

 // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
         //EventBus Model类
        Class eventType = subscriberMethod.eventType;
        //包装成订阅请求
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
        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++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        List> subscribedEvents = typesBySubscriber.get(subscriber);
        //将事件订阅,之后post会从typesBySubscriber中获取订阅者并发送事件
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        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).
                Set, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry, 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);
            }
        }
    }

以上就是订阅事件的处理了,遍历subscriberMethods集合,把每个subscriberMethods再次包装成订阅请求并添加进typesBySubscriber(hashmap)中,之后post或就会从中取出请求并给订阅者发送消息。
归根到底Event使用观察者模式+反射完成它的运作

好了,EventBus事件订阅部分讲完了。下一篇EventBus源码解析(二)post普通消息发送

你可能感兴趣的:(EventBus源码解析(一)EventBus事件订阅)