深扒 EventBus:register

上一篇:深扒 EventBus:getDefault

FindState

再看 EventBus.register 方法源码之前,我们先来了解 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<?> clazz;
    boolean skipSuperClasses;
    SubscriberInfo subscriberInfo;

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

    void recycle() {
        subscriberMethods.clear();
        anyMethodByEventType.clear();
        subscriberClassByMethodKey.clear();
        methodKeyBuilder.setLength(0);
        subscriberClass = null;
        clazz = null;
        skipSuperClasses = false;
        subscriberInfo = null;
    }

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

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

什么?看完很懵逼?这里我们可以简化一下

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;
    // clazz = subscriberClass
    Class<?> clazz;
    // 跳过父类(默认为false)
    boolean skipSuperClasses;
    // 订阅信息
    SubscriberInfo subscriberInfo;

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

    // 回收
    void recycle() {}

    // 检查添加
    boolean checkAdd(Method method, Class<?> eventType) {}

    // 检查添加方法的签名
    private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {}

    // 向上查找
    void moveToSuperclass() {}
}

我们可以从类的简化中获取需要的信息,这个其实就是用于保存被订阅类中的信息

接下来让我再看 SubscriberMethodFinder.prepareFindState 方法

这个方法其实就是在复用 FindState 对象,如果缓存池里面没有,就直接 new FindState,这种方式其实是用了享元设计模式,这样做的好处是什么呢?因为享元设计模式中的最大一个特点就是对象复用,那么问题又来了,为什么要复用对象呢?因为使用 FindState 次数非常多,为了避免重复创建导致不必要的内存浪费,所以 EventBus 采用享元设计模式来解决这一问题

SubscriberMethod

刚刚看完了 FindState 类,再来了解一下 SubscriberMethod 这个类是做什么的,先简单过一遍源码

/** EventBus内部使用并生成订阅者索引 */
/** Used internally by EventBus and generated subscriber indexes. */
public class SubscriberMethod {
    final Method method;
    final ThreadMode threadMode;
    final Class<?> eventType;
    final int priority;
    final boolean sticky;
    /** Used for efficient comparison */
    String methodString;

    public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
        this.method = method;
        this.threadMode = threadMode;
        this.eventType = eventType;
        this.priority = priority;
        this.sticky = sticky;
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        } else if (other instanceof SubscriberMethod) {
            checkMethodString();
            SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
            otherSubscriberMethod.checkMethodString();
            // Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
            return methodString.equals(otherSubscriberMethod.methodString);
        } else {
            return false;
        }
    }

    private synchronized void checkMethodString() {
        if (methodString == null) {
            // Method.toString has more overhead, just take relevant parts of the method
            StringBuilder builder = new StringBuilder(64);
            builder.append(method.getDeclaringClass().getName());
            builder.append('#').append(method.getName());
            builder.append('(').append(eventType.getName());
            methodString = builder.toString();
        }
    }

    @Override
    public int hashCode() {
        return method.hashCode();
    }
}

同样的套路,我们先把类简化一下

public class SubscriberMethod {
    // 反射的方法
    final Method method;
    // 线程调度
    final ThreadMode threadMode;
    // 参数类型
    final Class<?> eventType;
    // 优先级
    final int priority;
    // 是否为粘性事件
    final boolean sticky;

    public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
        this.method = method;
        this.threadMode = threadMode;
        this.eventType = eventType;
        this.priority = priority;
        this.sticky = sticky;
    }
}

这下真相大白了,这个 SubscriberMethod 就是专门记录被 @Subscribe 注解方法的一些信息,而 FindState 是专门记录订阅到 EventBus 中对象的一些信息。简单点来说,SubscriberMethod 是记录方法信息,而 FindState 是专门记录类的信息

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.

注册给定的订阅服务器来接收事件。订阅者必须调用{@link #unregister(Object)}
不再对接收事件感兴趣。
订阅者拥有必须由{@link Subscribe}注释的事件处理方法。
{@link Subscribe}注释还允许像{@link ThreadMode}和priority这样的配置。

接下来看一下 findSubscriberMethods 方法做了什么操作

private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();

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

    // 先判断一下这个 class 类型之前有没有实例注册过 EventBus
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) {
        // 如果有的话就不要再遍历一次了,直接将之前遍历的结果返回回去,提升执行效率
        return subscriberMethods;
    }

    // 这个字段正是 EventBusBuilder.ignoreGeneratedIndex 传过来的
    // 这个 EventBus 是支持编译时注解生成的方法,类似于 Butterknife
    // 这个字段一定要搞懂,不懂的一定要回去看我前面两篇文章
    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;
    }
}

关于 ignoreGeneratedIndex 这个字段的出处

public class EventBusBuilder {

    boolean ignoreGeneratedIndex;

    /** 翻译:强制使用反射,即使生成了索引(默认值:false) **/
    /** Forces the use of reflection even if there's a generated index (default: false). */
    public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) {
        this.ignoreGeneratedIndex = ignoreGeneratedIndex;
        return this;
    }
}

findUsingInfo

既然 ignoreGeneratedIndex 默认值为 false,那么让我们先看一下 findUsingInfo 方法的源码

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

    // FindState 类,还有 prepareFindState 方法刚刚已经讲过了,这里不再赘述
    FindState findState = prepareFindState();
    // 重置 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 {
            findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    return getMethodsAndRelease(findState);
}

让我们一层一层解析源码,到底代码的作用是什么

while (findState.clazz != null) {
    ......
    findState.moveToSuperclass();
}

class SubscriberMethodFinder {

    static class FindState {

        Class<?> subscriberClass; // 是否跳过父类
        Class<?> clazz;

        void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false; // 不跳过父类
        }

        void recycle() {
            subscriberClass = null;
            clazz = null;
        }

        // 让我们简单看一下这段代码
        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;
                }
            }
        }
    }
}

这是一段经过精简的源码,我们稍微看一下就能看懂,这是在查找被订阅对象全部的超类(父类)的被订阅的方法,特别是 moveToSuperclass 方法已经告诉我们了,当超类是系统类的时候不会再往上查找了,我们可以回顾一下 Object 类,它的完整包名是 java.lang.Object,也就是说到了 Object 类后会直接跳出,不会被遍历,因为 Object 类中不可能有被 @Subscribe 注解的方法,Activity 和 Fragment 也是同理

再看下一段代码,getSubscriberInfo 方法是块硬骨头,需要一点一点啃

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        // 让我们重点看一下这段代码的源码
        findState.subscriberInfo = getSubscriberInfo(findState);

        ......

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

private List<SubscriberInfoIndex> subscriberInfoIndexes;

// 看这个方法名就知道这个方法是干什么的了(获取订阅信息)
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) {
        // 遍历所有的索引(这里的索引是指 MyEventBusIndex 类,前面的文章已经介绍过了)
        for (SubscriberInfoIndex index : subscriberInfoIndexes) {
            SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
            if (info != null) {
                return info;
            }
        }
    }
    return null;
}

// 关于 List<SubscriberInfoIndex> 字段的来源可以看这里,前面的文章已经讲过的了
/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;

    static {
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();

        putIndex(new SimpleSubscriberInfo(com.gatewang.ksl.ui.fragment.PersonFragment.class, true,
                new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onLoginEvent", com.gatewang.ksl.event.LoginEvent.class, ThreadMode.MAIN),
            new SubscriberMethodInfo("onLoginOutEvent", com.gatewang.ksl.event.LoginOutEvent.class, ThreadMode.MAIN),
        }));

        putIndex(new SimpleSubscriberInfo(com.gatewang.ksl.ui.activity.MainActivity.class, true,
                new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("goBackHomeEvent", com.gatewang.ksl.event.GoBackHomeEvent.class, ThreadMode.MAIN),
        }));

        .........
    }

    private static void putIndex(SubscriberInfo info) {
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }

    @Override
    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }
}

看过这些代码相信你应该懂了,原来我们项目中使用 @Subscribe 注解地方的信息都在这里,那么为什么要保存在这里呢?好处在哪儿呢?,让我们再回顾一下刚刚讲过的 ignoreGeneratedIndex 这个字段

public class EventBusBuilder {

    boolean ignoreGeneratedIndex;

    /** 翻译:强制使用反射,即使生成了索引(默认值:false) **/
    /** Forces the use of reflection even if there's a generated index (default: false). */
    public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) {
        this.ignoreGeneratedIndex = ignoreGeneratedIndex;
        return this;
    }
}

现在我们能明白了,为什么默认不用强制使用反射,因为用反射来获取类和方法的信息比较耗性能,EventBus 出了一个 APT 自动生成代码插件,将项目中带有 @Subscribe 注解的地方保存到 MyEventBusIndex 中,这样我们就不需要通过反射获取了,这样是可以极大的提升执行效率

看完了 getSubscriberInfo 方法的作用,接下来看看剩下的代码

private List<SubscriberMethod> 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);
}

findState.subscriberInfo = getSubscriberInfo(findState);

// 查找 APT 生成的索引类有没有保存这个类的注解信息
if (findState.subscriberInfo != null) {
    // 如果有的话
    SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
    // 遍历被注解所有的方法
    for (SubscriberMethod subscriberMethod : array) {
        // 检查被注解方法有没有被添加到 FindState 对象中,有的话就不要重复添加了
        if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
            findState.subscriberMethods.add(subscriberMethod);
        }
    }
} else {
    // 如果没有的话,让我们重点看一下这段代码
    findUsingReflectionInSingleClass(findState);
}

// find Using Reflection In Single Class 翻译: 查找在单个类中使用反射
private void findUsingReflectionInSingleClass(FindState findState) {
    // 创建一个数组,用于存放被注解的方法信息
    Method[] methods;
    try {
        // 这比getMethods更快,特别是当订阅者是像 activity 这样的胖类时
        // 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 的,并且不能为
         *  private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC
         *  抽象方法,静态方法,接口方法,合成方法
         */
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {

            // 获取这个方法的参数类型
            Class<?>[] parameterTypes = method.getParameterTypes();

            // 这个方法的参数必须只能有一个
            if (parameterTypes.length == 1) {

                // 获取方法上面的注解,例如:@Subscribe(threadMode = ThreadMode.MAIN)
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                // 这个方法必须要有这个 @Subscribe 注解才会往下执行
                if (subscribeAnnotation != null) {

                    // 获取方法参数上面的类型
                    Class<?> eventType = parameterTypes[0];
                    // 检查有没有被添加到 FindState 对象中,有的话就不要重复添加了
                    if (findState.checkAdd(method, eventType)) {

                        // 获取需要被调用的线程类型
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                        // 添加这个方法的注解信息到 FindState 对象中
                        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");
        }
    }
}

// 简单看一下 @Subscribe 这个注解类
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {

    ThreadMode threadMode() default ThreadMode.POSTING; // 默认将该方法和消息发送方在同一个线程中执行

    /**
     * 如果为真,则传递最近的粘性事件(用
     * {@link EventBus#postSticky(Object)}到此订阅服务器(如果事件可用)。
     * 
     * If true, delivers the most recent sticky event (posted with
     * {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
     */
    boolean sticky() default false; // 默认不是粘性消息

    /** 
     * 订阅者优先级,以影响事件交付的顺序。
     * 在同一个交付线程内({@link ThreadMode}),优先级更高的订阅者将在之前接收事件
     * 其他优先级较低的。默认优先级为0。注意:优先级不影响顺序
     * 使用不同的{@link ThreadMode}的订阅者之间的传递!
     * 
     * 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; // 默认优先级为 0
}

看完了这个 findUsingInfo 方法的源码,我们大致了解了这个方法的作用和流程,其实就是在找被注解的类和方法,大致有两种方式,一种是通过自动生成的索引类 MyEventBusIndex(由 APT 自动生成的)获取到被注解的方法,这种方式比较高效,另一种是直接通过反射直接获取方法,这种效率会比较低下,所以 EventBus 默认会采用第一种方式,如果没有找到 MyEventBusIndex 类,则使用反射的方式获取

findUsingReflection

看完了 findUsingInfo ,再看 findUsingReflection

private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        findUsingReflectionInSingleClass(findState);
        findState.moveToSuperclass();
    }
    return getMethodsAndRelease(findState);
}

你会发现 findUsingReflection 就是 findUsingInfo 精简版,不信你自己比对一下

private List<SubscriberMethod> 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);
}

经过对比可以看出,findUsingReflection 没有用 getSubscriberInfo 方法查找索引类,而是直接通过反射获取所需要的信息

刚刚我们好像漏掉了一个方法 getMethodsAndRelease 没讲,这个方法在 findUsingReflection 和 findUsingInfo 的最后一行出现了,让我们来看一下它的源码

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
    // 创建一个新的集合对象,将 findState.subscriberMethods 这个集合的数据添加到新创建的集合中
    List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
    // 对 FindState 里面的对象进行回收
    findState.recycle();

    // 将使用过的 FindState 存放到缓存池中,方便下次复用
    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;
}

你是否似曾感觉好像有一段代码是和这个方法对应的,没错就是 prepareFindState 方法,前面已经讲过了

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

Subscription

在这里加一段小插曲,介绍一下 Subscription 类的作用

final class Subscription {

    // 被订阅的对象:EventBus.register(Object subscriber)
    final Object subscriber;

    // 被订阅的方法:@Subscribe
    final SubscriberMethod subscriberMethod;

    /**
     * 调用{@link EventBus#unregister(Object)}时为false,该函数由排队的事件交付检查
     * {@link EventBus#invokeSubscriber(PendingPost)}以防止竞争条件
     * 
     * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
     * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
     */
    volatile boolean active;

    Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
        this.subscriber = subscriber;
        this.subscriberMethod = subscriberMethod;
        active = true;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Subscription) {
            Subscription otherSubscription = (Subscription) other;
            return subscriber == otherSubscription.subscriber
                    && subscriberMethod.equals(otherSubscription.subscriberMethod);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
    }
}

从上面这些字段可以看出来,Subscription 其实就是包装了订阅对象和里面订阅的方法信息

subscribe

你以为 EventBus.register 的源码都看完了?其实就看了 findSubscriberMethods 中的两个方法而已,让我们继续往下看

public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);

    // 让我们重点看一下这段代码
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

// 这里使用了同步锁,EventBus 对线程安全的问题处理得很好啊
synchronized (this) {
    // 遍历刚刚由 findSubscriberMethods 返回的集合(存放被 @Subscribe 注解的方法信息)
    for (SubscriberMethod subscriberMethod : subscriberMethods) {
        // 接下来再重点看一下这个方法的源码
        subscribe(subscriber, subscriberMethod);
    }
}

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; // 根据事件的类型存放订阅事件集合
private final Map<Object, List<Class<?>>> typesBySubscriber; // 根据被订阅对象存放事件类型的集合
private final Map<Class<?>, Object> stickyEvents; // 粘性事件集合

// 必须在同步块中调用
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {

    // 获取事件的类型
    Class<?> eventType = subscriberMethod.eventType;
    // 对被订阅的对象和方法进行再次封装
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);

    // 获取这种类型的事件集合
    CopyOnWriteArrayList<Subscription> 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<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    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<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);
        }
    }
}

EventBus.unregister

总算把 EventBus.register 看完了,接下来看一看 EventBus.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 {
        // 这个对象没有被订阅过(EventBus.register)
        logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}

// 遍历事件类型集合
for (Class<?> eventType : subscribedTypes) {
    // 将这个被订阅对象和所注册的事件类型移除掉
    unsubscribeByEventType(subscriber, eventType);
}

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 有两种方式获取这个对象的订阅信息,第一种是通过 Apt 自动生成的索引类,第二种是通过反射直接获取类中注解的方法,显然第一种比较高效,EventBus 优先以第一种方式去获取, 第一种获取不到再使用第二种,如果用反射还获取不到,就会直接抛出异常,告诉开发者这个对象里面没有被 @Subscribe 注解的方法,所以这个对象不能被订阅到 EventBus 中(EventBus.register)。

如果通过第一种或者第二种可以获取得到的话,会将这些订阅的信息分别放到两个集合中,一个集合是按照订阅对象存放的订阅信息,EventBus.unregister 的时候会从这个集合中移除相应的订阅信息;而另一个集合是按照事件类型存放的订阅信息,可想而知 EventBus.post 会从这个集合获取相应的订阅信息,然后反射执行这些订阅的方法。

Android 技术讨论 Q 群:10047167

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者