EventBus(三)手写EventBus3.1.1

系列文章

EventBus(一) 简单使用,不使用反射,使用注解处理器
EventBus(二)使用反射的方式的原理
EventBus(三)手写EventBus3.1.1

EventBus的不足

发布粘性事件:触发了所有同类型订阅方法(粘性和非粘性)
粘性事件订阅方法无法第2次消费(很难满足复杂项目要求)
多次调用和移除粘性事件时,post会执行多次粘性事件订阅方法(非粘性正常)

本文章的解决方案

优化索引方法,让api更简单直接
重写注解处理器,方式: apt + javapoet (官方是传统写法)
弱化了线程池,使用缓存线程池替代
去除了对象池概念,考虑recycle问题。暂未测试内存泄漏情况
修复Subscription对象匹配bug,删除hashCode无用方法。

思路

通过apt+javapoet技术, 在编译时期,将注册了@Subscribe注解的方法,以class为key,多个方法的封装List为Value放到全局变量map中,存放在apt生成的java类中。在post的时候,使用apt生成的java类对象找到注册的方法,从而使用反射技术调用。 如果指定了线程模式,则需要有线程调度的实现。如果有指定顺序,则重新排列List的顺序 。

注解java-lib

build.gradle的配置

apply plugin: 'java-library'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
}

// java控制台输出中文乱码
tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
}

sourceCompatibility = "7"
targetCompatibility = "7"

线程模式枚举

/**
 * 线程模式
 */
public enum ThreadMode {

    // 订阅、发布在同一线程。避免了线程切换,也是推荐的默认模式
    POSTING,

    // 主线程(UI线程)中被调用,切勿耗时操作
    MAIN,

    // 用于网络访问等耗时操作,事件总线已完成的异步订阅通知线程。并使用线程池有效地重用
    ASYNC
}

事件订阅方法封装类

/**
 * 事件订阅方法封装类
 */
public class SubscriberMethod {

    private String methodName; // 订阅方法名
    private Method method; // 订阅方法,用于最后的自动执行订阅方法
    private ThreadMode threadMode; // 线程模式
    private Class eventType; // 事件对象Class,如:UserInfo.class
    private int priority; // 事件订阅优先级(实现思路:重排序集合中方法的顺序)
    private boolean sticky; // 是否粘性事件(实现思路:发送时存储,注册时判断粘性再激活)

    public SubscriberMethod(Class subscriberClass, String methodName,
                            Class eventType, ThreadMode threadMode, int priority, boolean sticky) {
        this.methodName = methodName;
        this.threadMode = threadMode;
        this.eventType = eventType;
        this.priority = priority;
        this.sticky = sticky;
        try {
            // 订阅所属类(参考源码:AbstractSubscriberInfo.java - 72行)
            method = subscriberClass.getDeclaredMethod(methodName, eventType);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    public String getMethodName() {
        return methodName;
    }

    public Method getMethod() {
        return method;
    }

    public ThreadMode getThreadMode() {
        return threadMode;
    }

    public Class getEventType() {
        return eventType;
    }

    public int getPriority() {
        return priority;
    }

    public boolean isSticky() {
        return sticky;
    }
}

所有事件集合封装类

/**
 * 所有事件集合
 */
public class EventBeans implements SubscriberInfo {

    // 订阅者对象Class,如:MainActivity.class
    private final Class subscriberClass;
    // 订阅方法数组,参考SimpleSubscriberInfo.java 25行
    private final SubscriberMethod[] methodInfos;

    public EventBeans(Class subscriberClass, SubscriberMethod[] methodInfos) {
        this.subscriberClass = subscriberClass;
        this.methodInfos = methodInfos;
    }

    @Override
    public Class getSubscriberClass() {
        return subscriberClass;
    }

    @Override
    public synchronized SubscriberMethod[] getSubscriberMethods() {
        return methodInfos;
    }
}

获取订阅所有事件的接口

public interface SubscriberInfo {

    // 订阅所属类,比如:MainActivity
    Class getSubscriberClass();

    // 获取订阅所属类中所有订阅事件的方法(此处不使用List是因为注解处理器每次都要list.clear(),麻烦!)
    SubscriberMethod[] getSubscriberMethods();
}

索引接口

/**
 * 所有的事件订阅方法,生成索引接口
 */
public interface SubscriberInfoIndex {

    /**
     * 生成索引接口,通过订阅者对象(MainActivity.class)获取所有订阅方法
     *
     * @param subscriberClass 订阅者对象Class,如:MainActivity.class
     * @return 事件订阅方法封装类
     */
    SubscriberInfo getSubscriberInfo(Class subscriberClass);
}

注解


@Target(ElementType.METHOD) // 该注解作用在方法之上
@Retention(RetentionPolicy.CLASS) // 要在编译时进行一些预处理操作,注解会在class文件中存在
public @interface Subscribe {

    // 线程模式,默认推荐POSTING(订阅、发布在同一线程)
    ThreadMode threadMode() default ThreadMode.POSTING;

    // 是否使用粘性事件
    boolean sticky() default false;

    // 事件订阅优先级,在同一个线程中。数值越大优先级越高。
    int priority() default 0;
}

注解处理器java-lib

build.gradle的配置

apply plugin: 'java-library'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // As-3.4.1 + gradle5.1.1-all + auto-service:1.0-rc4
    compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'

    // 帮助我们通过类调用的形式来生成Java代码
    implementation "com.squareup:javapoet:1.9.0"
    // 引入annotation,处理@Subscribe注解
    implementation project(':eventbus_annotation')
}

// java控制台输出中文乱码
tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
}

sourceCompatibility = "7"
targetCompatibility = "7"

注解处理器


/**
 * 编码此类1句话:细心再细心,出了问题debug真的不好调试
 */
// 用来生成 META-INF/services/javax.annotation.processing.Processor 文件
@AutoService(Processor.class)
// 允许/支持的注解类型,让注解处理器处理
@SupportedAnnotationTypes({Constants.SUBSCRIBE_ANNOTATION_TYPES})
// 指定JDK编译版本
@SupportedSourceVersion(SourceVersion.RELEASE_7)
// 注解处理器接收的参数
@SupportedOptions({Constants.PACKAGE_NAME, Constants.CLASS_NAME})
public class SubscribeProcessor extends AbstractProcessor {

    // 操作Element工具类 (类、函数、属性都是Element)
    private Elements elementUtils;

    // type(类信息)工具类,包含用于操作TypeMirror的工具方法
    private Types typeUtils;

    // Messager用来报告错误,警告和其他提示信息
    private Messager messager;

    // 文件生成器 类/资源,Filter用来创建新的类文件,class文件以及辅助文件
    private Filer filer;

    // APT包名
    private String packageName;

    // APT类名
    private String className;

    // 临时map存储,用来存放订阅方法信息,生成路由组类文件时遍历
    // key:组名"MainActivity", value:MainActivity中订阅方法集合
    private final Map> methodsByClass = new HashMap<>();

    // 该方法主要用于一些初始化的操作,通过该方法的参数ProcessingEnvironment可以获取一些列有用的工具类
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        // 初始化
        elementUtils = processingEnvironment.getElementUtils();
        typeUtils = processingEnvironment.getTypeUtils();
        messager = processingEnvironment.getMessager();
        filer = processingEnvironment.getFiler();

        // 通过ProcessingEnvironment去获取对应的参数
        Map options = processingEnvironment.getOptions();
        if (!EmptyUtils.isEmpty(options)) {
            packageName = options.get(Constants.PACKAGE_NAME);
            className = options.get(Constants.CLASS_NAME);
            messager.printMessage(Diagnostic.Kind.NOTE,
                    "packageName >>> " + packageName + " / className >>> " + className);
        }

        // 必传参数判空(乱码问题:添加java控制台输出中文乱码)
        if (EmptyUtils.isEmpty(packageName) || EmptyUtils.isEmpty(className)) {
            messager.printMessage(Diagnostic.Kind.ERROR, "注解处理器需要的参数为空,请在对应build.gradle配置参数");
        }
    }

    /**
     * 相当于main函数,开始处理注解
     * 注解处理器的核心方法,处理具体的注解,生成Java文件
     *
     * @param set              使用了支持处理注解的节点集合
     * @param roundEnvironment 当前或是之前的运行环境,可以通过该对象查找的注解。
     * @return true 表示后续处理器不会再处理(已经处理完成)
     */
    @Override
    public boolean process(Set set, RoundEnvironment roundEnvironment) {
        // 一旦有类之上使用@Subscribe注解
        if (!EmptyUtils.isEmpty(set)) {
            // 获取所有被 @Subscribe 注解的 元素集合
            Set elements = roundEnvironment.getElementsAnnotatedWith(Subscribe.class);

            if (!EmptyUtils.isEmpty(elements)) {
                // 解析元素
                try {
                    parseElements(elements);
                    return true;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return true;
        }
        return false;
    }

    // 解析所有被 @Subscribe 注解的 类元素集合
    private void parseElements(Set elements) throws IOException {

        // 遍历节点
        for (Element element : elements) {
            // @Subscribe注解只能在方法之上(尽量避免使用instanceof进行判断)
            if (element.getKind() != ElementKind.METHOD) {
                messager.printMessage(Diagnostic.Kind.ERROR, "仅解析@Subscribe注解在方法上元素");
                return;
            }
            // 强转方法元素
            ExecutableElement method = (ExecutableElement) element;
            // 检查方法,条件:订阅方法必须是非静态的,公开的,参数只能有一个
            if (checkHasNoErrors(method)) {
                // 获取封装订阅方法的类(方法上一个节点)
                TypeElement classElement = (TypeElement) method.getEnclosingElement();

                // 以类名为key,保存订阅方法
                List methods = methodsByClass.get(classElement);
                if (methods == null) {
                    methods = new ArrayList<>();
                    methodsByClass.put(classElement, methods);
                }
                methods.add(method);
            }

            messager.printMessage(Diagnostic.Kind.NOTE, "遍历注解方法:" + method.getSimpleName().toString());
        }

        // 通过Element工具类,获取SubscriberInfoIndex类型
        TypeElement subscriberIndexType = elementUtils.getTypeElement(Constants.SUBSCRIBERINFO_INDEX);

        // 生成类文件
        createFile(subscriberIndexType);
    }

    private void createFile(TypeElement subscriberIndexType) throws IOException {
        // 添加静态块代码:SUBSCRIBER_INDEX = new HashMap();
        CodeBlock.Builder codeBlock = CodeBlock.builder();
        codeBlock.addStatement("$N = new $T<$T, $T>()",
                Constants.FIELD_NAME,
                HashMap.class,
                Class.class,
                SubscriberInfo.class);

        // 双层循环,第一层遍历被@Subscribe注解的方法所属类。第二层遍历每个类中所有订阅的方法
        for (Map.Entry> entry : methodsByClass.entrySet()) {
            // 此处不能使用codeBlock,会造成错误嵌套
            CodeBlock.Builder contentBlock = CodeBlock.builder();
            CodeBlock contentCode = null;
            String format;
            for (int i = 0; i < entry.getValue().size(); i++) {
                // 获取每个方法上的@Subscribe注解中的注解值
                Subscribe subscribe = entry.getValue().get(i).getAnnotation(Subscribe.class);
                // 获取订阅事件方法所有参数
                List parameters = entry.getValue().get(i).getParameters();
                // 获取订阅事件方法名
                String methodName = entry.getValue().get(i).getSimpleName().toString();
                // 注意:此处还可以做检查工作,比如:参数类型必须是类或接口类型(这里缩减了)
                TypeElement parameterElement = (TypeElement) typeUtils.asElement(parameters.get(0).asType());
                // 如果是最后一个添加,则无需逗号结尾
                if (i == entry.getValue().size() - 1) {
                    format = "new $T($T.class, $S, $T.class, $T.$L, $L, $L)";
                } else {
                    format = "new $T($T.class, $S, $T.class, $T.$L, $L, $L),\n";
                }
                // new SubscriberMethod(MainActivity.class, "abc", UserInfo.class, ThreadMode.POSTING, 0, false)
                contentCode = contentBlock.add(format,
                        SubscriberMethod.class,
                        ClassName.get(entry.getKey()),
                        methodName,
                        ClassName.get(parameterElement),
                        ThreadMode.class,
                        subscribe.threadMode(),
                        subscribe.priority(),
                        subscribe.sticky())
                        .build();
            }

            if (contentCode != null) {
                // putIndex(new EventBeans(MainActivity.class, new SubscriberMethod[] {)
                codeBlock.beginControlFlow("putIndex(new $T($T.class, new $T[]",
                        EventBeans.class,
                        ClassName.get(entry.getKey()),
                        SubscriberMethod.class)
                        // 嵌套的精华(尝试了很多次,有更好的方式请告诉我)
                        .add(contentCode)
                        // ))}
                        .endControlFlow("))");
            } else {
                messager.printMessage(Diagnostic.Kind.ERROR, "注解处理器双层循环发生错误!");
            }
        }

        // 全局属性:Map, SubscriberMethod>
        TypeName fieldType = ParameterizedTypeName.get(
                ClassName.get(Map.class), // Map
                ClassName.get(Class.class), // Map
        );

        // putIndex方法参数:putIndex(SubscriberInfo info)
        ParameterSpec putIndexParameter = ParameterSpec.builder(
                ClassName.get(SubscriberInfo.class),
                Constants.PUTINDEX_PARAMETER_NAME)
                .build();

        // putIndex方法配置:private static void putIndex(SubscriberMethod info) {
        MethodSpec.Builder putIndexBuidler = MethodSpec
                .methodBuilder(Constants.PUTINDEX_METHOD_NAME) // 方法名
                .addModifiers(Modifier.PRIVATE, Modifier.STATIC) // private static修饰符
                .addParameter(putIndexParameter); // 添加方法参数
        // 不填returns默认void返回值

        // putIndex方法内容:SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
        putIndexBuidler.addStatement("$N.put($N.getSubscriberClass(), $N)",
                Constants.FIELD_NAME,
                Constants.PUTINDEX_PARAMETER_NAME,
                Constants.PUTINDEX_PARAMETER_NAME);

        // getSubscriberInfo方法参数:Class subscriberClass
        ParameterSpec getSubscriberInfoParameter = ParameterSpec.builder(
                ClassName.get(Class.class),
                Constants.GETSUBSCRIBERINFO_PARAMETER_NAME)
                .build();

        // getSubscriberInfo方法配置:public SubscriberMethod getSubscriberInfo(Class subscriberClass) {
        MethodSpec.Builder getSubscriberInfoBuidler = MethodSpec
                .methodBuilder(Constants.GETSUBSCRIBERINFO_METHOD_NAME) // 方法名
                .addAnnotation(Override.class) // 重写方法注解
                .addModifiers(Modifier.PUBLIC) // public修饰符
                .addParameter(getSubscriberInfoParameter) // 方法参数
                .returns(SubscriberInfo.class); // 方法返回值

        // getSubscriberInfo方法内容:return SUBSCRIBER_INDEX.get(subscriberClass);
        getSubscriberInfoBuidler.addStatement("return $N.get($N)",
                Constants.FIELD_NAME,
                Constants.GETSUBSCRIBERINFO_PARAMETER_NAME);

        // 构建类
        TypeSpec typeSpec = TypeSpec.classBuilder(className)
                // 实现SubscriberInfoIndex接口
                .addSuperinterface(ClassName.get(subscriberIndexType))
                // 该类的修饰符
                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                // 添加静态块(很少用的api)
                .addStaticBlock(codeBlock.build())
                // 全局属性:private static final Map, SubscriberMethod> SUBSCRIBER_INDEX
                .addField(fieldType, Constants.FIELD_NAME, Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
                // 第一个方法:加入全局Map集合
                .addMethod(putIndexBuidler.build())
                // 第二个方法:通过订阅者对象(MainActivity.class)获取所有订阅方法
                .addMethod(getSubscriberInfoBuidler.build())
                .build();

        // 生成类文件:EventBusIndex
        JavaFile.builder(packageName, // 包名
                typeSpec) // 类构建完成
                .build() // JavaFile构建完成
                .writeTo(filer); // 文件生成器开始生成类文件
    }

    /**
     * 检查方法,条件:订阅方法必须是非静态的,公开的,参数只能有一个
     *
     * @param element 方法元素
     * @return 检查是否通过
     */
    private boolean checkHasNoErrors(ExecutableElement element) {
        // 不能为static静态方法
        if (element.getModifiers().contains(Modifier.STATIC)) {
            messager.printMessage(Diagnostic.Kind.ERROR, "订阅事件方法不能是static静态方法", element);
            return false;
        }

        // 必须是public修饰的方法
        if (!element.getModifiers().contains(Modifier.PUBLIC)) {
            messager.printMessage(Diagnostic.Kind.ERROR, "订阅事件方法必须是public修饰的方法", element);
            return false;
        }

        // 订阅事件方法必须只有一个参数
        List parameters = ((ExecutableElement) element).getParameters();
        if (parameters.size() != 1) {
            messager.printMessage(Diagnostic.Kind.ERROR, "订阅事件方法有且仅有一个参数", element);
            return false;
        }
        return true;
    }

}

总控制module

build.gradle


    implementation project(':eventbus_annotation')

增加注解的依赖。

JavaBean封装

/**
 * 临时JavaBean对象,也可以直接写在EventBus做为变量
 */
final class Subscription {

    final Object subscriber; // 订阅者MainActivity.class
    final SubscriberMethod subscriberMethod; // 订阅的方法

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

    @Override
    public boolean equals(Object other) {
        // 必须重写方法,检测激活粘性事件重复调用(同一对象注册多个)
        if (other instanceof Subscription) {
            Subscription otherSubscription = (Subscription) other;
            // 删除官方:subscriber == otherSubscription.subscriber判断条件
            // 原因:粘性事件Bug,多次调用和移除时重现,参考Subscription.java 37行
            return subscriberMethod.equals(otherSubscription.subscriberMethod);
        } else {
            return false;
        }
    }
}

总控制类


/**
 * ArrayList的底层是数组,查询和修改直接根据索引可以很快找到对应的元素(替换)
 * 而增加和删除就涉及到数组元素的移动,所以会比较慢
 * 

* CopyOnWriteArrayList实现了List接口(读写分离) * Vector是增删改查方法都加了synchronized,保证同步,但是每个方法执行的时候都要去获得锁,性能就会大大下降 * 而CopyOnWriteArrayList 只是在增删改上加锁,但是读不加锁,在读方面的性能就好于Vector *

* CopyOnWriteArrayList支持读多写少的并发情况 */ public class EventBus { // volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存 private static volatile EventBus defaultInstance; // 索引接口 private SubscriberInfoIndex subscriberInfoIndexes; // 订阅者类型集合,比如:订阅者MainActivity订阅了哪些EventBean,或者解除订阅的缓存。 // key:订阅者MainActivity.class,value:EventBean集合 private Map>> typesBySubscriber; // 方法缓存:key:订阅者MainActivity.class,value:订阅方法集合 private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>(); // EventBean缓存,key:UserInfo.class,value:订阅者(可以是多个Activity)中所有订阅的方法集合 private Map, CopyOnWriteArrayList> subscriptionsByEventType; // 粘性事件缓存,key:UserInfo.class,value:UserInfo private final Map, Object> stickyEvents; // 发送(子线程) - 订阅(主线程) private Handler handler; // 发送(主线程) - 订阅(子线程) private ExecutorService executorService; private EventBus() { // 初始化缓存集合 typesBySubscriber = new HashMap<>(); subscriptionsByEventType = new HashMap<>(); stickyEvents = new HashMap<>(); // Handler高级用法:将handler放在主线程使用 handler = new Handler(Looper.getMainLooper()); // 创建一个子线程(缓存线程池) executorService = Executors.newCachedThreadPool(); } // 单例,全局唯一,参考EventBus.java 80行 public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; } // 添加索引(简化),接口 = 接口实现类,参考EventBusBuilder.java 136行 public void addIndex(SubscriberInfoIndex index) { subscriberInfoIndexes = index; } // 注册 / 订阅事件,参考EventBus.java 138行 public void register(Object subscriber) { // 获取MainActivity.class Class subscriberClass = subscriber.getClass(); // 寻找(MainActivity.class)订阅方法集合 List subscriberMethods = findSubscriberMethods(subscriberClass); synchronized (this) { // 同步锁,并发少可考虑删除(参考源码) for (SubscriberMethod subscriberMethod : subscriberMethods) { // 遍历后,开始订阅 subscribe(subscriber, subscriberMethod); } } } // 寻找(MainActivity.class)订阅方法集合,参考SubscriberMethodFinder.java 55行 private List findSubscriberMethods(Class subscriberClass) { // 从方法缓存中读取 List subscriberMethods = METHOD_CACHE.get(subscriberClass); // 找到了缓存,直接返回 if (subscriberMethods != null) { return subscriberMethods; } // 找不到,从APT生成的类文件中寻找 subscriberMethods = findUsingInfo(subscriberClass); if (subscriberMethods != null) { // 存入缓存 METHOD_CACHE.put(subscriberClass, subscriberMethods); } return subscriberMethods; } // 遍历中……并开始订阅,参考EventBus.java 149行 private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { // 获取订阅方法参数类型,如:UserInfo.class Class eventType = subscriberMethod.getEventType(); // 临时对象存储 Subscription subscription = new Subscription(subscriber, subscriberMethod); // 读取EventBean缓存 CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { // 初始化集合 subscriptions = new CopyOnWriteArrayList<>(); // 存入缓存 subscriptionsByEventType.put(eventType, subscriptions); } else { if (subscriptions.contains(subscription)) { Log.e("netease >>> ", subscriber.getClass() + "重复注册粘性事件!"); // 执行多次粘性事件,但不添加到集合,避免订阅方法多次执行 sticky(subscriberMethod, eventType, subscription); return; } } // 订阅方法优先级处理。第一次进来肯定是0,参考EventBus.java 163行 int size = subscriptions.size(); // 这里的i <= size,否则进不了下面条件 for (int i = 0; i <= size; i++) { // 如果满足任一条件则进入循环(第1次 i = size = 0) // 第2次,size不为0,新加入的订阅方法匹配集合中所有订阅方法的优先级 if (i == size || subscriberMethod.getPriority() > subscriptions.get(i).subscriberMethod.getPriority()) { // 如果新加入的订阅方法优先级大于集合中某订阅方法优先级,则插队到它之前一位 if (!subscriptions.contains(subscription)) subscriptions.add(i, subscription); // 优化:插队成功就跳出(找到了加入集合点) break; } } // 订阅者类型集合,比如:订阅者MainActivity订阅了哪些EventBean,或者解除订阅的缓存 List> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); // 存入缓存 typesBySubscriber.put(subscriber, subscribedEvents); } // 注意:subscribe()方法在遍历过程中,所以一直在添加 subscribedEvents.add(eventType); sticky(subscriberMethod, eventType, subscription); } // 抽取原因:可执行多次粘性事件,而不会出现闪退,参考EventBus.java 158行 private void sticky(SubscriberMethod subscriberMethod, Class eventType, Subscription subscription) { // 粘性事件触发:注册事件就激活方法,因为整个源码只有此处遍历了。 // 最佳切入点原因:1,粘性事件的订阅方法加入了缓存。2,注册时只有粘性事件直接激活方法(隔离非粘性事件) // 新增开关方法弊端:粘性事件未在缓存中,无法触发订阅方法。且有可能多次执行post()方法 if (subscriberMethod.isSticky()) { // 参考EventBus.java 178行 // 源码中做了继承关系的处理,也说明了迭代效率和更改数据结构方便查找,这里就省略了(真实项目极少) Object stickyEvent = stickyEvents.get(eventType); // 发送事件 到 订阅者的所有订阅方法,并激活方法 if (stickyEvent != null) postToSubscription(subscription, stickyEvent); } } // 从APT生成的类文件中寻找订阅方法集合,参考SubscriberMethodFinder.java 64行 private List findUsingInfo(Class subscriberClass) { // app在运行时寻找索引,报错了则说明没有初始化索引方法 if (subscriberInfoIndexes == null) { throw new RuntimeException("未添加索引方法:addIndex()"); } // 接口持有实现类的引用 SubscriberInfo info = subscriberInfoIndexes.getSubscriberInfo(subscriberClass); // 数组转List集合,参考EventBus生成的APT类文件 if (info != null) return Arrays.asList(info.getSubscriberMethods()); return null; } // 是否已经注册 / 订阅,参考EventBus.java 217行 public synchronized boolean isRegistered(Object subscriber) { return typesBySubscriber.containsKey(subscriber); } // 解除某订阅者关系,参考EventBus.java 239行 public synchronized void unregister(Object subscriber) { // 从缓存中移除 List> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { // 移除前清空集合 subscribedTypes.clear(); typesBySubscriber.remove(subscriber); } } // 发送粘性事件,最终还是调用了post方法,参考EventBus.java 301行 public void postSticky(Object event) { // 同步锁保证并发安全(小项目可忽略此处) synchronized (stickyEvents) { // 加入粘性事件缓存集合 stickyEvents.put(event.getClass(), event); } // 巨坑!!!源码这么写我也不知道什么意图。恶心的后果:只要参数匹配,粘性/非粘性订阅方法全部执行 // post(event); } // 获取指定类型的粘性事件,参考EventBus.java 314行 public T getStickyEvent(Class eventType) { // 同步锁保证并发安全(小项目可忽略此处) synchronized (stickyEvents) { // cast方法做转换类型时安全措施(简化stickyEvents.get(eventType)) return eventType.cast(stickyEvents.get(eventType)); } } // 移除指定类型的粘性事件(此处返回值看自己需求,可为boolean),参考EventBus.java 325行 public T removeStickyEvent(Class eventType) { // 同步锁保证并发安全(小项目可忽略此处) synchronized (stickyEvents) { return eventType.cast(stickyEvents.remove(eventType)); } } // 移除所有粘性事件,参考EventBus.java 352行 public void removeAllStickyEvents() { // 同步锁保证并发安全(小项目可忽略此处) synchronized (stickyEvents) { // 清理集合 stickyEvents.clear(); } } // 发送消息 / 事件 public void post(Object event) { // 此处两个参数,简化了源码,参考EventBus.java 252 - 265 - 384 - 400行 postSingleEventForEventType(event, event.getClass()); } // 为EventBean事件类型发布单个事件(遍历),EventBus核心:参数类型必须一致!!! private void postSingleEventForEventType(Object event, Class eventClass) { // 从EventBean缓存中,获取所有订阅者和订阅方法 CopyOnWriteArrayList subscriptions; synchronized (this) { // 同步锁,保证并发安全 subscriptions = subscriptionsByEventType.get(eventClass); } // 判空,健壮性代码 if (subscriptions != null && !subscriptions.isEmpty()) { for (Subscription subscription : subscriptions) { // 遍历,寻找发送方指定的EventBean,匹配的订阅方法的EventBean postToSubscription(subscription, event); } } } // 发送事件 到 订阅者的所有订阅方法(遍历中……),参考参考EventBus.java 427行 private void postToSubscription(final Subscription subscription, final Object event) { // 匹配订阅方的线程模式 switch (subscription.subscriberMethod.getThreadMode()) { case POSTING: // 订阅、发布在同一线程 invokeSubscriber(subscription, event); break; case MAIN: // 订阅方是主线程,则主 - 主 if (Looper.myLooper() == Looper.getMainLooper()) { invokeSubscriber(subscription, event); } else { // 订阅方是子线程,则子 - 主 handler.post(new Runnable() { @Override public void run() { invokeSubscriber(subscription, event); } }); } break; case ASYNC: // 订阅方是主线程,则主 - 子 if (Looper.myLooper() == Looper.getMainLooper()) { // 主线程 - 子线程,创建一个子线程(缓存线程池) executorService.execute(new Runnable() { @Override public void run() { invokeSubscriber(subscription, event); } }); } else { // 订阅方是子线程,则子 - 子 invokeSubscriber(subscription, event); } break; default: throw new IllegalStateException("未知线程模式!" + subscription.subscriberMethod.getThreadMode()); } } // 执行订阅方法(被注解方法自动执行)参考EventBus.java 505行 private void invokeSubscriber(Subscription subscription, Object event) { try { // 无论3.0之前还是之后。最后一步终究逃不过反射! subscription.subscriberMethod.getMethod().invoke(subscription.subscriber, event); } catch (Exception e) { e.printStackTrace(); } } // 清理静态缓存(视项目规模调用) public static void clearCaches() { METHOD_CACHE.clear(); } }

你可能感兴趣的:(android)