register(注冊(cè))
SubscriberMethod
eventbus注冊(cè)的時(shí)候回遍歷查詢已經(jīng)被Subscribe
注解的方法(Method)
包含:
- method:包含了這個(gè)方法的全部信息,通過(guò)這個(gè)屬性,可以反射出該方法摔桦,進(jìn)行調(diào)用轴猎;
- threadMode:該方法在什么什么線程下調(diào)用光督;
- eventType: 事件的類(lèi)型雕憔,會(huì)通過(guò)該類(lèi)型自動(dòng)往該種類(lèi)型的eventType上追加任務(wù)酬蹋。
1萧吠、尋找List<SubscriberMethod>
2左冬、將上面找到的List<SubscriberMethod>
依次進(jìn)行注冊(cè)
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
這樣,會(huì)形成:
如上圖的數(shù)據(jù)結(jié)構(gòu)怎憋,這樣就很明確了又碌,一個(gè)EventType對(duì)應(yīng)其中所有的對(duì)其注冊(cè)的Subscription
,而Subscription
形如:
這樣就很清晰了:
在Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
這個(gè)map中绊袋,我們存儲(chǔ)了在何種EventType
上面注冊(cè)的各種不同注冊(cè)者Subscription
上面的不同的方法SubscriberMethod
毕匀。
2.1、我們可以想象:
-
subscriptionsByEventType
因該是至少使用HashMap
作為基本的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)的癌别; -
CopyOnWriteArrayList<Subscription>
也需要做判斷重復(fù)的工作皂岔,因?yàn)椋翰恍枰胖脙杀橥粚?duì)象中各種被@Subscribe
注解的方法。
所以:
如果你在同一個(gè)類(lèi)中重復(fù)調(diào)用register
方法進(jìn)行注冊(cè)展姐,
譬如:
EventBus.getDefault().register(this);
EventBus.getDefault().register(this);
會(huì)拋出異常躁垛,這是顯然的。
2.2圾笨、如何進(jìn)行注冊(cè)的
3教馆、發(fā)送事件(post)
注意可能會(huì)在多線程中進(jìn)行EventBus的使用,并進(jìn)行時(shí)間的register和post擂达,eventBus有必要進(jìn)行多線程方面的考慮土铺。
使用ThreadLocal初始化并存儲(chǔ)該線程需要進(jìn)行發(fā)送的事件的容器。
關(guān)于
ThreadLocal
的相關(guān)知識(shí),可以參考: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悲敷、發(fā)送線程相關(guān)狀態(tài)的設(shè)置
3.2究恤、 postSingleEvent
postSingleEvent(eventQueue.remove(0), postingState);
這段代碼出現(xiàn)一個(gè)疑問(wèn):
postingState
中已經(jīng)持有了eventQueue
,為何仍舊需要這樣調(diào)用?
3.2.1后德、eventInheritance
EventBus
支持發(fā)送的EventClass是否是可以繼承的,應(yīng)用場(chǎng)景就是:
為了代碼的架構(gòu)清晰部宿,某些想用的事件不需要傳遞不同的參數(shù),而只需要將各種不同的參數(shù)類(lèi)都繼承于同一個(gè)BaseClass
或者實(shí)現(xiàn)同一個(gè)BaseInterface
瓢湃。
譬如:小明和小紅是兄妹理张,兩人在學(xué)校里獲得了********同樣的********獎(jiǎng)項(xiàng)(這里比喻需要發(fā)送相同的事件),現(xiàn)在學(xué)校要把獎(jiǎng)狀發(fā)給小明和小紅箱季,當(dāng)然涯穷,最為直接的就是學(xué)校分別把兩張獎(jiǎng)狀給小明和小紅棍掐,但是藏雏,也可以這樣:********學(xué)校把獎(jiǎng)狀給了小明和小紅的媽媽?zhuān)蓩寢屩苯咏唤o兄妹兩人********。這里可以想象到:小明和小紅都“********繼承********”于媽媽作煌。
這樣掘殴,單個(gè)事件就開(kāi)始發(fā)送了。
3.3粟誓、執(zhí)行
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處理的消息
其實(shí)就是使用Handler,發(fā)送消息到Main Looper中進(jìn)行輪詢鹰服。
mainThreadPoster.enqueue(subscription, event);
其一病瞳、PendingPost
這是一個(gè)用于構(gòu)造具體的方法的實(shí)體,用于傳遞給Loop是main的Handler進(jìn)行消息的處理悲酷。
值得一提的是:這是一個(gè)需要進(jìn)行反復(fù)構(gòu)造的實(shí)體套菜,反復(fù)的進(jìn)行new構(gòu)造會(huì)影響性能,所以構(gòu)造了一個(gè)pendingPostPool
進(jìn)行緩存设易。這個(gè)pool的最大的容量是10000逗柴。
synchronized (pendingPostPool) {
// Don't let the pool grow indefinitely
if (pendingPostPool.size() < 10000) {
pendingPostPool.add(pendingPost);
}
}
其二、maxMillisInsideHandleMessage
在構(gòu)造在UI Thread進(jìn)行發(fā)送信息的HandlerPoster
的時(shí)候顿肺,會(huì)傳遞一個(gè)maxMillisInsideHandleMessage
戏溺,但是,在想:都是同步方法屠尊,計(jì)算耗時(shí)的意義何在翱趸觥?
3.3.2讼昆、在UI Thread處理需要在子線程處理的消息
這種比較容易托享,使用線程池執(zhí)行就行了。
eventBus.getExecutorService().execute(this);