register(注冊)
SubscriberMethod
eventbus注冊的時候回遍歷查詢已經被Subscribe
注解的方法(Method)
包含:
- method:包含了這個方法的全部信息,通過這個屬性,可以反射出該方法,進行調用;
- threadMode:該方法在什么什么線程下調用;
- eventType: 事件的類型,會通過該類型自動往該種類型的eventType上追加任務。
1、尋找List<SubscriberMethod>
2、將上面找到的List<SubscriberMethod>
依次進行注冊
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
這樣,會形成:
如上圖的數據結構,這樣就很明確了,一個EventType對應其中所有的對其注冊的Subscription
,而Subscription
形如:
這樣就很清晰了:
在Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
這個map中,我們存儲了在何種EventType
上面注冊的各種不同注冊者Subscription
上面的不同的方法SubscriberMethod
。
2.1、我們可以想象:
-
subscriptionsByEventType
因該是至少使用HashMap
作為基本的數據存儲結構的; -
CopyOnWriteArrayList<Subscription>
也需要做判斷重復的工作,因為:不需要放置兩遍同一對象中各種被@Subscribe
注解的方法。
所以:
如果你在同一個類中重復調用register
方法進行注冊,
譬如:
EventBus.getDefault().register(this);
EventBus.getDefault().register(this);
會拋出異常,這是顯然的。
2.2、如何進行注冊的
3、發送事件(post)
注意可能會在多線程中進行EventBus的使用,并進行時間的register和post,eventBus有必要進行多線程方面的考慮。
使用ThreadLocal初始化并存儲該線程需要進行發送的事件的容器。
關于
ThreadLocal
的相關知識,可以參考:http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal/
/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<Object>();
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}
3.1、發送線程相關狀態的設置
3.2、 postSingleEvent
postSingleEvent(eventQueue.remove(0), postingState);
這段代碼出現一個疑問:
postingState
中已經持有了eventQueue
,為何仍舊需要這樣調用?
3.2.1、eventInheritance
EventBus
支持發送的EventClass是否是可以繼承的,應用場景就是:
為了代碼的架構清晰,某些想用的事件不需要傳遞不同的參數,而只需要將各種不同的參數類都繼承于同一個BaseClass
或者實現同一個BaseInterface
。
譬如:小明和小紅是兄妹,兩人在學校里獲得了********同樣的********獎項(這里比喻需要發送相同的事件),現在學校要把獎狀發給小明和小紅,當然,最為直接的就是學校分別把兩張獎狀給小明和小紅,但是,也可以這樣:********學校把獎狀給了小明和小紅的媽媽,由媽媽直接交給兄妹兩人********。這里可以想象到:小明和小紅都“********繼承********”于媽媽。
這樣,單個事件就開始發送了。
3.3、執行
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
// 在子線程處理需要在UI Thread處理的消息
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
// 在UI Thread處理需要在子線程處理的消息
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
3.3.1、在子線程處理需要在UI Thread處理的消息
其實就是使用Handler,發送消息到Main Looper中進行輪詢。
mainThreadPoster.enqueue(subscription, event);
其一、PendingPost
這是一個用于構造具體的方法的實體,用于傳遞給Loop是main的Handler進行消息的處理。
值得一提的是:這是一個需要進行反復構造的實體,反復的進行new構造會影響性能,所以構造了一個pendingPostPool
進行緩存。這個pool的最大的容量是10000。
synchronized (pendingPostPool) {
// Don't let the pool grow indefinitely
if (pendingPostPool.size() < 10000) {
pendingPostPool.add(pendingPost);
}
}
其二、maxMillisInsideHandleMessage
在構造在UI Thread進行發送信息的HandlerPoster
的時候,會傳遞一個maxMillisInsideHandleMessage
,但是,在想:都是同步方法,計算耗時的意義何在啊?
3.3.2、在UI Thread處理需要在子線程處理的消息
這種比較容易,使用線程池執行就行了。
eventBus.getExecutorService().execute(this);