文章目录

  • 一、注册订阅方法
  • 二、完整代码示例

一、注册订阅方法


订阅方法注册的过程就是将 订阅方法参数类型 和 订阅类 + 订阅方法 封装类 , 保存到 Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType 集合中 , 该集合的键值含义如下 :

  • Key - 订阅者方法事件参数类型
  • Value - 封装 订阅者对象 与 订阅方法 的 MySubscription 集合

同时 , 还要为 取消注册 准备数据 , 取消注册数据存放在 Map<Object, List<Class<?>>> typesBySubscriber 集合中 , 该集合的键值含义如下 :

  • Key - 订阅者对象
  • Value - 订阅者方法参数集合

1. 获取事件类型 : 获取订阅方法接收的参数类型 ;

        // 获取订阅方法接收的参数类型Class<?> eventType = subscriberMethod.getEventType();

2. 获取订阅者 : 获取 Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType 集合中 eventType 参数类型对应的 订阅者封装类 ( 封装 订阅者对象 + 订阅方法 ) 集合 ;

        // 获取 eventType 参数类型对应的 订阅者封装类 ( 封装 订阅者对象 + 订阅方法 ) 集合CopyOnWriteArrayList<MySubscription> subscriptions =subscriptionsByEventType.get(eventType);

3. 订阅者为空处理 : 如果获取的集合为空 , 说明 eventType 参数对应的订阅方法一个也没有注册过 , 这里先创建一个集合 , 放到 subscriptionsByEventType 键值对中 ;

        // 如果获取的集合为空 , 说明 eventType 参数对应的订阅方法一个也没有注册过//      这里先创建一个集合 , 放到 subscriptionsByEventType 键值对中if (subscriptions == null) {// 创建集合subscriptions = new CopyOnWriteArrayList<>();// 将集合设置到 subscriptionsByEventType 键值对集合中subscriptionsByEventType.put(eventType, subscriptions);}

4. 设置订阅者集合 : 封装 订阅者对象 + 订阅方法 对象 , 将创建的 订阅者对象 + 订阅方法 对象 添加到 CopyOnWriteArrayList 集合中 ;

        // 封装 订阅者对象 + 订阅方法 对象MySubscription subscription = new MySubscription(subscriber, subscriberMethod);// 将创建的 订阅者对象 + 订阅方法 对象 添加到  CopyOnWriteArrayList 集合中subscriptions.add(subscription);

5. 设置取消注册数据 : Map<Object, List<Class<?>>> typesBySubscriber 集合用于取消注册时 , 通过订阅者对象 查找 该订阅者对象中所有订阅方法的 事件参数类型 集合 , 然后通过事件类型 , 就可以去 Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType 集合中查找相关数据 ;

        // 为取消注册准备数据//      设置 Map<Object, List<Class<?>>> typesBySubscriberList<Class<?>> eventTypes = typesBySubscriber.get(subscriber);if (eventTypes == null) {// 创建新的集合, 用于存放订阅方法的参数类型eventTypes = new ArrayList<>();// 将新的集合设置到 Map<Object, List<Class<?>>> typesBySubscriber 集合中typesBySubscriber.put(subscriber, eventTypes);}// 将新的 订阅方法类型 放入到集合中eventTypes.add(eventType);

部分代码示例 :

    /*** 方法订阅*      将 订阅方法参数类型 和 订阅类 + 订阅方法 封装类 , 保存到*      Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType 集合中*          Key - 订阅者方法事件参数类型*          Value - 封装 订阅者对象 与 订阅方法 的 MySubscription 集合** 取消注册数据准备*      取消注册数据存放在 Map<Object, List<Class<?>>> typesBySubscriber 集合中*          Key - 订阅者对象*          Value - 订阅者方法参数集合** @param subscriber    订阅者对象* @param subscriberMethod        订阅方法*/private void subscribe(Object subscriber, MySubscriberMethod subscriberMethod) {// 获取订阅方法接收的参数类型Class<?> eventType = subscriberMethod.getEventType();// 获取 eventType 参数类型对应的 订阅者封装类 ( 封装 订阅者对象 + 订阅方法 ) 集合CopyOnWriteArrayList<MySubscription> subscriptions =subscriptionsByEventType.get(eventType);// 如果获取的集合为空 , 说明 eventType 参数对应的订阅方法一个也没有注册过//      这里先创建一个集合 , 放到 subscriptionsByEventType 键值对中if (subscriptions == null) {// 创建集合subscriptions = new CopyOnWriteArrayList<>();// 将集合设置到 subscriptionsByEventType 键值对集合中subscriptionsByEventType.put(eventType, subscriptions);}// 封装 订阅者对象 + 订阅方法 对象MySubscription subscription = new MySubscription(subscriber, subscriberMethod);// 将创建的 订阅者对象 + 订阅方法 对象 添加到  CopyOnWriteArrayList 集合中subscriptions.add(subscription);// 为取消注册准备数据//      设置 Map<Object, List<Class<?>>> typesBySubscriberList<Class<?>> eventTypes = typesBySubscriber.get(subscriber);if (eventTypes == null) {// 创建新的集合, 用于存放订阅方法的参数类型eventTypes = new ArrayList<>();// 将新的集合设置到 Map<Object, List<Class<?>>> typesBySubscriber 集合中typesBySubscriber.put(subscriber, eventTypes);}// 将新的 订阅方法类型 放入到集合中eventTypes.add(eventType);}

二、完整代码示例


完整代码示例 :

package com.eventbus_demo.myeventbus;import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;public class MyEventBus {/*** 方法缓存*      Key - 订阅类类型*      Value - 订阅方法 MySubscriberMethod 的集合* 取名与 EventBus 一致*/private static final Map<Class<?>, List<MySubscriberMethod>> METHOD_CACHE = new HashMap<>();/*** 解除注册时使用*      Key - 订阅者对象*      Value - 订阅者对象中所有的订阅方法的事件参数类型集合** 根据该订阅者对象 , 查找所有订阅方法的事件参数类型 ,  然后再到  METHOD_CACHE 中 ,*      根据事件参数类型 , 查找对应的 MySubscriberMethod 集合*      MySubscriberMethod 中封装 订阅者对象 + 订阅方法**/private final Map<Object, List<Class<?>>> typesBySubscriber;/*** Key - 订阅者方法事件参数类型* Value - 封装 订阅者对象 与 订阅方法 的 MySubscription 集合* 在构造函数中初始化* CopyOnWriteArrayList 在写入数据时会拷贝一个副本 ,*      写完之后 , 将引用指向新的副本 ,*      该集合的线程安全级别很高*/private final Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType;/*** 全局单例*/private static MyEventBus instance;private MyEventBus() {subscriptionsByEventType = new HashMap<>();typesBySubscriber = new HashMap<>();}public static MyEventBus getInstance() {if (instance == null) {instance = new MyEventBus();}return instance;}/*** 注册订阅者* @param subscriber*/public void register(Object subscriber) {// 获取订阅者所属类Class<?> clazz = subscriber.getClass();// 查找订阅方法List<MySubscriberMethod> subscriberMethods = findSubscriberMethods(clazz);// 遍历所有订阅方法 , 进行订阅//      首先确保查找到的订阅方法不为空 , 并且个数大于等于 1 个if (subscriberMethods != null && !subscriberMethods.isEmpty()) {for (MySubscriberMethod method : subscriberMethods) {// 正式进行订阅subscribe(subscriber, method);}}}/*** 方法订阅*      将 订阅方法参数类型 和 订阅类 + 订阅方法 封装类 , 保存到*      Map<Class<?>, CopyOnWriteArrayList<MySubscription>> subscriptionsByEventType 集合中*          Key - 订阅者方法事件参数类型*          Value - 封装 订阅者对象 与 订阅方法 的 MySubscription 集合** 取消注册数据准备*      取消注册数据存放在 Map<Object, List<Class<?>>> typesBySubscriber 集合中*          Key - 订阅者对象*          Value - 订阅者方法参数集合** @param subscriber    订阅者对象* @param subscriberMethod        订阅方法*/private void subscribe(Object subscriber, MySubscriberMethod subscriberMethod) {// 获取订阅方法接收的参数类型Class<?> eventType = subscriberMethod.getEventType();// 获取 eventType 参数类型对应的 订阅者封装类 ( 封装 订阅者对象 + 订阅方法 ) 集合CopyOnWriteArrayList<MySubscription> subscriptions =subscriptionsByEventType.get(eventType);// 如果获取的集合为空 , 说明 eventType 参数对应的订阅方法一个也没有注册过//      这里先创建一个集合 , 放到 subscriptionsByEventType 键值对中if (subscriptions == null) {// 创建集合subscriptions = new CopyOnWriteArrayList<>();// 将集合设置到 subscriptionsByEventType 键值对集合中subscriptionsByEventType.put(eventType, subscriptions);}// 封装 订阅者对象 + 订阅方法 对象MySubscription subscription = new MySubscription(subscriber, subscriberMethod);// 将创建的 订阅者对象 + 订阅方法 对象 添加到  CopyOnWriteArrayList 集合中subscriptions.add(subscription);// 为取消注册准备数据//      设置 Map<Object, List<Class<?>>> typesBySubscriberList<Class<?>> eventTypes = typesBySubscriber.get(subscriber);if (eventTypes == null) {// 创建新的集合, 用于存放订阅方法的参数类型eventTypes = new ArrayList<>();// 将新的集合设置到 Map<Object, List<Class<?>>> typesBySubscriber 集合中typesBySubscriber.put(subscriber, eventTypes);}// 将新的 订阅方法类型 放入到集合中eventTypes.add(eventType);}/*** 根据订阅方法的事件参数查找订阅方法* @param subscriberClass   订阅者对象的类型* @return*/private List<MySubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {// 获取 Class<?> clazz 参数类型对应的 订阅者封装类List<MySubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);// 此处后期重构, 减少缩进if (subscriberMethods == null) {// 说明是首次获取 , 初始化 METHOD_CACHE 缓存// 反射获取 Class<?> subscriberClass 中的所有订阅方法subscriberMethods = findByReflection(subscriberClass);if (! subscriberMethods.isEmpty()) {METHOD_CACHE.put(subscriberClass, subscriberMethods);}} else {// 如果当前不是第一次获取, 则直接返回从 METHOD_CACHE 缓存中获取的 订阅者封装类 集合return subscriberMethods;}// 该分支走不到return null;}/*** 通过反射获取 Class<?> subscriberClass 订阅方法* @param subscriberClass 订阅类* @return*/private List<MySubscriberMethod> findByReflection(Class<?> subscriberClass) {// 要返回的 MySubscriberMethod 集合List<MySubscriberMethod> subscriberMethods = new ArrayList<>();// 通过反射获取所有带 @MySubscribe 注解的方法Method[] methods = subscriberClass.getMethods();// 遍历所有的方法 , 查找注解for (Method method : methods) {// 获取方法修饰符int modifiers = method.getModifiers();// 获取方法参数Class<?>[] params = method.getParameterTypes();// 确保修饰符必须是 public , 参数长度必须是 1if (modifiers == Modifier.PUBLIC && params.length == 1) {// 获取 MySubscribe 注解MySubscribe annotation = method.getAnnotation(MySubscribe.class);// 获取注解不为空if (annotation != null) {// 获取线程模式MyThreadMode threadMode = annotation.threadMode();// 此时已经完全确定该方法是一个订阅方法 , 直接进行封装MySubscriberMethod subscriberMethod = new MySubscriberMethod(method,         // 方法对象threadMode,     // 线程模式params[0]       // 事件参数);// 加入到返回集合中subscriberMethods.add(subscriberMethod);}}}return subscriberMethods;}}

【EventBus】事件通信框架 ( 订阅方法注册 | 注册 事件类型 - 订阅类 + 订阅方法 到指定集合 | 取消注册 数据准备 )相关推荐

  1. 【EventBus】事件通信框架 ( 实现几个关键的封装类 | 消息中心 | 订阅注解 | 订阅方法封装 | 订阅对象-方法封装 | 线程模式 )

    文章目录 一.消息中心 二.订阅方法时的注解 三.订阅方法封装 四.订阅对象-方法封装 五.线程模式 一.消息中心 此处暂时只实现一个单例类 , 后续 注册订阅者 , 处理事件传递 , 取消注册订阅者 ...

  2. 【EventBus】事件通信框架 ( 取消注册 | 获取事件参数类型 | 根据事件类型获取订阅者 | 移除相关订阅者 )

    文章目录 一.取消注册订阅者 二.完整代码示例 一.取消注册订阅者 取消注册操作 : 从 Map<Object, List<Class<?>>> typesBySu ...

  3. 【EventBus】事件通信框架 ( 总结 | 手写事件通信框架完整代码示例 | 测试上述框架 )

    文章目录 一.消息中心 二.订阅方法时的注解 三.订阅方法封装 四.订阅对象-方法封装 五.线程模式 六.Activity 中测试上述框架 七.博客源码 一.消息中心 该消息中心是事件通信框架的核心代 ...

  4. 【EventBus】事件通信框架 ( 发送事件 | 判断发布线程是否是主线程 | 子线程切换主线程 | 主线程切换子线程 )

    文章目录 前言 一.根据不同的线程模式进行不同的线程切换操作 二.完整代码示例 前言 发布线程发布事件之后 , 消息中心需要转发这些事件 , 并执行相应的订阅方法 ; 在转发的过程中 , 需要针对订阅 ...

  5. 【EventBus】事件通信框架 ( 订阅方法注册 | 检查订阅方法缓存 | 反射获取订阅类中的订阅方法 )

    文章目录 一.检查订阅方法缓存 二.反射获取订阅类中的订阅方法 三.完整代码示例 一.检查订阅方法缓存 注册订阅者时 , 只传入一个订阅者类对象 , 其它信息都需要通过反射获取 ; 1. 获取订阅者类 ...

  6. 【EventBus】事件通信框架 ( 订阅类-订阅方法缓存集合 | 事件类型-订阅者集合 | 订阅对象-事件类型集合 )

    文章目录 前言 一.订阅类-订阅方法缓存集合 二.事件类型-订阅者集合 三.订阅对象-事件类型集合 前言 首先声明几个数据结构 , 参考 [EventBus]EventBus 源码解析 ( 注册订阅者 ...

  7. 【EventBus】事件通信框架 ( 发送事件 | 根据事件类型获取订阅者 | 调用订阅方法 )

    文章目录 一.根据事件类型获取订阅者 二.调用订阅方法 一.根据事件类型获取订阅者 接收到了 发布者 Publisher 发送给本消息中心 的 Event 消息事件对象 , 将该事件对象转发给相应接收 ...

  8. java的字节码无法显示_【java】查看Java字节码文件内容的方法+使用javap找不到类 解决方法...

    研究synchronized底层实现,涉及到查看java字节码的需要 前提是,你的PC已经成功安装了JDK并别配置了环境变量. ==========查看方法========= 一.javap查看简约字 ...

  9. javaSE-day04--ArrayList基本用方法、类内定义方法和方法重载、静态方法static(类的方法)、工具方法(static)的定义和使用

    ArrayList基本用方法 package day04;import java.util.ArrayList;public class ArrayListDemo {public static vo ...

最新文章

  1. 华为正式宣布养猪,网友沸腾:支持华为自救!
  2. python 代理使用方法简介
  3. 【Flutter】Hero 动画 ( Hero 动画使用流程 | 创建 Hero 动画核心组件 | 创建源页面 | 创建目的页面 | 页面跳转 )
  4. 重新学习一下ABAP里面的逻辑数据库
  5. matlab矩阵中的 *、/、\、.*
  6. python执行过程_Python threading模块condition原理及运行流程详解
  7. 【Web缓存机制系列】2 – Web浏览器的缓存机制
  8. 如何查看Android项目的gradle版本和路径
  9. https 配置自建ca
  10. android 正三角,倒三角的实现代码
  11. 基于 SIP 的会议系统框架(草稿)
  12. 基于云平台的电力供电设备远程监控系统
  13. item_get_app - 根据ID取商品详情原数据
  14. 代正通_ChromeBook怎么刷windows系统||Linux教程
  15. 华为发布MetaAAU,能耗降低30%,性能节能双提升
  16. 中国石油大学-《现代应用文写作》期末网考题
  17. Ubuntu系统中mplayer查找rmvb视频解码器的过程解析
  18. 关于开发中遇到的一些问题记录
  19. Heatmap Plot with ggplot2 【R】
  20. python快速实现2048小游戏

热门文章

  1. 扩展KMP --- HDU 3613 Best Reward
  2. Ubuntu 12.04 MySQL改utf-8 启动不了
  3. 自定义UISegmentedControl
  4. iOS pods更新失败
  5. mysql 日志文件mysql-bin文件清除方法,和mysql-bin相关文件的配置
  6. for语句之打印三角形问题
  7. awk 统计数据在文件中的出现次数
  8. 新建一个doophp项目
  9. 数据结构之【数组和广义表】复习题
  10. 使用rem适配不同屏幕的移动设备