【EventBus】EventBus 源码解析 ( 注册订阅者 | 注册订阅方法详细过程 )
文章目錄
- 前言
- 一、EventBus 注冊(cè)訂閱者
- 二、注冊(cè)訂閱方法的具體過程
- 三、Subscription 類
前言
在上一篇博客 【EventBus】EventBus 源碼解析 ( 注冊(cè)訂閱者 | 訂閱方法 | 查找訂閱方法 ) 中 , 介紹了注冊(cè)訂閱者的第一個(gè)步驟 , 查找訂閱者 ;
首先要獲取當(dāng)前的 List<SubscriberMethod> subscriberMethods 訂閱方法集合 , 該集合從 SubscriberMethodFinder 的緩存 Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE 獲取 , 該緩存是在第一次獲取訂閱方法時(shí)生成 , 之后獲取都直接從緩存中獲取即可 ;
METHOD_CACHE 緩存生成策略 : 如果是第一次獲取訂閱方法 , 緩存是空的 , 此時(shí)通過反射獲取該 訂閱類 所有符合條件的訂閱方法 , 將 訂閱方法 封裝到 SubscriberMethod 中 , 然后添加到 findState.subscriberMethods 集合中 ;
一、EventBus 注冊(cè)訂閱者
獲取到訂閱方法集合后 , 然后開始遍歷訂閱方法集合 , 調(diào)用 subscribe 方法 , 注冊(cè)訂閱者 ;
public class EventBus {/*** 注冊(cè)給定訂閱服務(wù)器以接收事件。訂閱者一旦對(duì)接收事件不再感興趣,就必須調(diào)用{@link#unregister(Object)}。* <p/>* 訂閱服務(wù)器具有必須由{@link Subscribe}注釋的事件處理方法。* {@link Subscribe}注釋還允許類似{@link ThreadMode}和優(yōu)先級(jí)的配置。*/public void register(Object subscriber) {Class<?> subscriberClass = subscriber.getClass();// 1. 獲取 訂閱者 集合 , 查找當(dāng)前訂閱類中符合條件的訂閱方法集合 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);// 2. 遍歷 訂閱者 集合 , 進(jìn)行事件訂閱 , 保存數(shù)據(jù) , 這些數(shù)據(jù)就是一些映射關(guān)系 synchronized (this) {for (SubscriberMethod subscriberMethod : subscriberMethods) {subscribe(subscriber, subscriberMethod);}}} }二、注冊(cè)訂閱方法的具體過程
獲取訂閱方法參數(shù)類型 , 可以是任意類型 , 自定義的 MessageEvent 消息類型 ;
subscribe(Object subscriber, SubscriberMethod subscriberMethod)封裝 Subscription 對(duì)象 , Subscription 中封裝了一個(gè)訂閱者對(duì)象和一個(gè)訂閱方法 ;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);從 Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType 成員變量中獲取 Subscription 集合 , 該 HashMap 的用途是保存當(dāng)前的 eventType 對(duì)應(yīng)的所有的訂閱類和訂閱方法 , 以便消息中心獲取對(duì)應(yīng)類型的消息后 , 可以順利將其傳遞給相應(yīng)訂閱方法 ;
- Key 是事件類型對(duì)象 ;
- Value 是 Subscription 集合 , Subscription 中封裝了一個(gè)訂閱者對(duì)象和一個(gè)訂閱方法
CopyOnWriteArrayList 是線程安全集合 , 寫入數(shù)據(jù)的時(shí)候會(huì)拷貝一份出來 , 不會(huì)影響其它線程讀取該集合的操作
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);如果上述集合中沒有保存本次遍歷的數(shù)據(jù) , 則將訂閱方法信息保存到上述集合中 ;
if (subscriptions == null) {subscriptions = new CopyOnWriteArrayList<>();// 保存鍵值對(duì)subscriptionsByEventType.put(eventType, subscriptions);} else {if (subscriptions.contains(newSubscription)) {throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "+ eventType);}}如果訂閱方法設(shè)置了優(yōu)先級(jí)注解屬性 , 則處理訂閱方法優(yōu)先級(jí) , 重新進(jìn)行排列 ;
int size = subscriptions.size();for (int i = 0; i <= size; i++) {// 處理訂閱方法優(yōu)先級(jí) , 重新進(jìn)行排列 if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {subscriptions.add(i, newSubscription);break;}}向 Map<Object, List<Class<?>>> typesBySubscriber 成員變量 添加 訂閱者對(duì)象 - 訂閱方法參數(shù)類型集合 鍵值對(duì) , 該成員變量的作用是取消注冊(cè)時(shí)查找相關(guān)的訂閱方法 ;
// Map<Object, List<Class<?>>> typesBySubscriber// Key : 訂閱者對(duì)象// Value : 訂閱方法參數(shù)類型集合 // 取消注冊(cè)時(shí) , 需要使用該方法 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);if (subscribedEvents == null) {subscribedEvents = new ArrayList<>();typesBySubscriber.put(subscriber, subscribedEvents);}subscribedEvents.add(eventType);注冊(cè)訂閱方法代碼示例 :
/*** EventBus是Java和Android的中央發(fā)布/訂閱事件系統(tǒng)。* 事件被發(fā)布({@link#post(Object)})到總線,總線將其傳遞給具有匹配處理程序的訂閱者* 事件類型的方法。* 要接收事件,訂閱者必須使用{@link#register(Object)}將自己注冊(cè)到總線。* 一旦注冊(cè),訂閱服務(wù)器將接收事件,直到調(diào)用{@link#unregister(Object)}。* 事件處理方法必須由{@link Subscribe}注釋,必須是公共的,不返回任何內(nèi)容(void),* 并且只有一個(gè)參數(shù)(事件)。*/ public class EventBus {// 該方法必須在同步代碼塊中調(diào)用 private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {// 獲取訂閱方法參數(shù)類型 , 可以是任意類型 , 自定義的 MessageEvent 消息類型Class<?> eventType = subscriberMethod.eventType;// Subscription 中封裝了一個(gè)訂閱者對(duì)象和一個(gè)訂閱方法 Subscription newSubscription = new Subscription(subscriber, subscriberMethod);// Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType 成員變量 // Key 是事件類型對(duì)象 // Value 是 Subscription 集合 , Subscription 中封裝了一個(gè)訂閱者對(duì)象和一個(gè)訂閱方法 // 該 HashMap 的用途是保存當(dāng)前的 eventType 對(duì)應(yīng)的所有的訂閱類和訂閱方法 // 以便消息中心獲取對(duì)應(yīng)類型的消息后 , 可以順利將其傳遞給相應(yīng)訂閱方法 // CopyOnWriteArrayList 是線程安全集合 , 寫入數(shù)據(jù)的時(shí)候會(huì)拷貝一份出來 , 不會(huì)影響其它線程讀取該集合的操作CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);// 如果上述集合中沒有保存本次遍歷的數(shù)據(jù) , 則將訂閱方法信息保存到上述集合中 if (subscriptions == null) {subscriptions = new CopyOnWriteArrayList<>();// 保存鍵值對(duì)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++) {// 處理訂閱方法優(yōu)先級(jí) , 重新進(jìn)行排列 if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {subscriptions.add(i, newSubscription);break;}}// Map<Object, List<Class<?>>> typesBySubscriber// Key : 訂閱者對(duì)象// Value : 訂閱方法參數(shù)類型集合 // 取消注冊(cè)時(shí) , 需要使用該方法 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);if (subscribedEvents == null) {subscribedEvents = new ArrayList<>();typesBySubscriber.put(subscriber, subscribedEvents);}subscribedEvents.add(eventType);// 處理方法粘性相關(guān)業(yè)務(wù)邏輯if (subscriberMethod.sticky) {if (eventInheritance) {// 必須考慮eventType的所有子類的現(xiàn)有粘性事件。// 注意:迭代所有事件可能效率低下,因?yàn)橛泻芏嗾承允录?#xff0c;// 因此,應(yīng)更改數(shù)據(jù)結(jié)構(gòu)以允許更高效的查找// 例如,存儲(chǔ)超類子類的附加映射: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);}}} }三、Subscription 類
Subscription 類中封裝了一個(gè)訂閱者對(duì)象和一個(gè)訂閱方法
final class Subscription {final Object subscriber;final SubscriberMethod subscriberMethod; }總結(jié)
以上是生活随笔為你收集整理的【EventBus】EventBus 源码解析 ( 注册订阅者 | 注册订阅方法详细过程 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【EventBus】EventBus 源
- 下一篇: 【EventBus】EventBus 源