【EventBus】事件通信框架 ( 订阅方法注册 | 注册 事件类型 - 订阅类 + 订阅方法 到指定集合 | 取消注册 数据准备 )
文章目錄
- 一、注冊訂閱方法
- 二、完整代碼示例
一、注冊訂閱方法
訂閱方法注冊的過程就是將 訂閱方法參數類型 和 訂閱類 + 訂閱方法 封裝類 , 保存到 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】事件通信框架 ( 订阅方法注册 | 注册 事件类型 - 订阅类 + 订阅方法 到指定集合 | 取消注册 数据准备 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【EventBus】事件通信框架 ( 订
- 下一篇: 【EventBus】事件通信框架 ( 发