EventBus三之手写EventBus

目录

  • 项目模块描述
  • eventbus_annotation模块
  • eventbus_compiler模块
  • eventbus模块
  • 代码传送门

项目模块描述

在这里插入图片描述

eventbus类图

在这里插入图片描述

eventbus时序图

在这里插入图片描述

eventbus_annotation 实现

a)定义注解类Subscribe

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

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

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

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

b)定义ThreadMode

public enum ThreadMode {
    // 订阅、发布在同一线程。避免了线程切换,也是推荐的默认模式
    POSTING,
    // 主线程(UI线程)中被调用,切勿耗时操作
    MAIN,
    // 用于网络访问等耗时操作,事件总线已完成的异步订阅通知线程。并使用线程池有效地重用
    ASYNC
}

c)定义订阅方法的描述类

public interface SubscriberInfo {
    // 订阅所属类,比如:MainActivity
    Class<?> getSubscriberClass();
    // 获取订阅所属类中所有订阅事件的方法(此处不使用List是因为注解处理器每次都要list.clear(),麻烦!)
    SubscriberMethod[] getSubscriberMethods();
}

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

d)定义订阅索引接口

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

eventbus_compiler 实现

// 注解处理器的实现

/**
 * 编码此类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<TypeElement, List<ExecutableElement>> 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<String, String> 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<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        // 一旦有类之上使用@Subscribe注解
        if (!EmptyUtils.isEmpty(set)) {
            // 获取所有被 @Subscribe 注解的 元素集合
            Set<? extends Element> 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<? extends Element> 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<ExecutableElement> 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<Class, SubscriberInfo>();
        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<TypeElement, List<ExecutableElement>> 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<? extends VariableElement> 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<Class<?>, SubscriberMethod>
        TypeName fieldType = ParameterizedTypeName.get(
                ClassName.get(Map.class), // Map
                ClassName.get(Class.class), // Map<Class,
                ClassName.get(SubscriberInfo.class) // Map<Class, SubscriberMethod>
        );

        // 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<Class<?>, 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<? extends VariableElement> parameters = ((ExecutableElement) element).getParameters();
        if (parameters.size() != 1) {
            messager.printMessage(Diagnostic.Kind.ERROR, "订阅事件方法有且仅有一个参数", element);
            return false;
        }
        return true;
    }

}

EventBus的实现

public class EventBus {

    // volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存
    private static volatile EventBus defaultInstance;
    // 索引接口
    private SubscriberInfoIndex subscriberInfoIndexes;
    // 订阅者类型集合,比如:订阅者MainActivity订阅了哪些EventBean,或者解除订阅的缓存。
    // key:订阅者MainActivity.class,value:EventBean集合
    private Map<Object, List<Class<?>>> typesBySubscriber;
    // 方法缓存:key:订阅者MainActivity.class,value:订阅方法集合
    private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
    // EventBean缓存,key:UserInfo.class,value:订阅者(可以是多个Activity)中所有订阅的方法集合
    private Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    // 粘性事件缓存,key:UserInfo.class,value:UserInfo
    private final Map<Class<?>, 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<SubscriberMethod> subscriberMethods = findSubscriberMethods(subscriberClass);
        synchronized (this) { // 同步锁,并发少可考虑删除(参考源码)
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                // 遍历后,开始订阅
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

    // 寻找(MainActivity.class)订阅方法集合,参考SubscriberMethodFinder.java 55行
    private List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        // 从方法缓存中读取
        List<SubscriberMethod> 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<Subscription> 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<Class<?>> 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<SubscriberMethod> 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<Class<?>> 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> T getStickyEvent(Class<T> eventType) {
        // 同步锁保证并发安全(小项目可忽略此处)
        synchronized (stickyEvents) {
            // cast方法做转换类型时安全措施(简化stickyEvents.get(eventType))
            return eventType.cast(stickyEvents.get(eventType));
        }
    }

    // 移除指定类型的粘性事件(此处返回值看自己需求,可为boolean),参考EventBus.java 325行
    public <T> T removeStickyEvent(Class<T> 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<Subscription> 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();
    }
}

javaPoet生成的类文件格式为:

public final class EventBusIndex implements SubscriberInfoIndex {
  private static final Map<Class, SubscriberInfo> SUBSCRIBER_INDEX;

  static {
    SUBSCRIBER_INDEX = new HashMap<Class, SubscriberInfo>();
    putIndex(new EventBeans(MainActivity.class, new SubscriberMethod[] {
      new SubscriberMethod(MainActivity.class, "handleMessageEvent", MessageEvent.class, ThreadMode.MAIN, 0, false)} ));
  }

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

  @Override
  public SubscriberInfo getSubscriberInfo(Class subscriberClass) {
    return SUBSCRIBER_INDEX.get(subscriberClass);
  }
}

源码传送门

发布了87 篇原创文章 · 获赞 6 · 访问量 1万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 精致技术 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览