LocalBroadcastManager
-
單例獲取LocalBroadcastManager實(shí)體邮弹,dooublecheck
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this)
-
注冊(cè)廣播接收者腌乡,
lbm.registerReceiver(mrevicer, new IntentFilter("LOCAL_ACTION"));
構(gòu)建一個(gè)廣播信息實(shí)體ReceiverRecord entry = new ReceiverRecord(filter, receiver)到ArrayList中
最后action的string做key,包含ReceiverRecord 的ArrayList做value放入HashMap mActions 中mActions.put(action, entries)
-
發(fā)生廣播
lbm.sendBroadcast(new Intent().setAction("LOCAL_ACTION").putExtra("text","ni shi local"));
從mActions中獲取廣播匹配"LOCAL_ACTION"的實(shí)體ReceiverRecord的集合
循環(huán)集合得到ReceiverRecord對(duì)每個(gè)進(jìn)行math与纽,把match的結(jié)果放入集合mPendingBroadcasts,然后發(fā)生message
內(nèi)部類Handler處理消息調(diào)用executePendingBroadcasts()
從集合mPendingBroadcasts中拿到每個(gè)receiver調(diào)用receiver.onReceive(mAppContext, br.intent)filter.match(action, type, scheme, data, categories, "LocalBroadcastManager")
-
取消廣播
從mActions中取出對(duì)應(yīng)action的集合
然后有當(dāng)前對(duì)象影所,就從集合中移除lbm.unregisterReceiver(mrevicer);
優(yōu)點(diǎn)比全局廣播效率高猴娩,
缺點(diǎn)勺阐,使用Android原生API渊抽,不適合javalib懒闷,LocalBroadcastManager的傳遞不方便需要context不是所有module都有context對(duì)象毛雇,組件化能用但是不適合
EventBus
EventBus可以代替Android傳統(tǒng)的Intent,Handler,Broadcast或接口函數(shù),在Fragment,Activity,Service線程之間傳遞數(shù)據(jù)灵疮,只是傳遞震捣。Handler是很多時(shí)候逃不掉的坑蒿赢。
register
通過(guò)getDefault獲取EventBus實(shí)例羡棵,這是一條默認(rèn)的事件總線,通過(guò)單例模式實(shí)現(xiàn),其構(gòu)造函數(shù)是Public的皂冰,也可以通過(guò)EventBus.builder().build()來(lái)創(chuàng)建多條事件總線,一般在oncreate中創(chuàng)建养篓。
EventBus.getDefault().register(this);
//這是一個(gè)構(gòu)建者模式+鏈?zhǔn)秸{(diào)用秃流,build之前可以鏈?zhǔn)秸{(diào)用添加參數(shù)
EventBus.builder().build()
unregister
如果是默認(rèn)直接通過(guò)下面的方法取消柳弄,自己新建的就要拿到之前保留的對(duì)象舶胀,然后調(diào)用unregister方法
EventBus.getDefault().unregister(this);
post
發(fā)送消息,可以是任意對(duì)象嚣伐。
EventBus.getDefault().post(daLaBa);
Subscribe
- threadMode
POSTING
默認(rèn)的模式,開銷最小的模式,因?yàn)槁暶鳛镻OSTING的訂閱者會(huì)在發(fā)布的同一個(gè)線程調(diào)用糖赔,發(fā)布者在主線程那么訂閱者也就在主線程,反之亦,避免了線程切換,如果不確定是否有耗時(shí)操作轩端,謹(jǐn)慎使用挂捻,因?yàn)榭赡苁窃谥骶€程發(fā)布MAIN
主線程調(diào)用,視發(fā)布線程不同處理不同,如果發(fā)布者在主線程那么直接調(diào)用(非阻塞式),如果發(fā)布者不在主線程那么阻塞式調(diào)用MAIN_ORDERED
和MAIN差不多,主線程調(diào)用刻撒,和MAIN不同的是他保證了post是非阻塞式的(默認(rèn)走M(jìn)AIN的非主線程的邏輯,所以可以做到非阻塞)BACKGROUND
在子線程調(diào)用,如果發(fā)布在子線程那么直接在發(fā)布線程調(diào)用,如果發(fā)布在主線程那么將開啟一個(gè)子線程來(lái)調(diào)用,這個(gè)子線程是阻塞式的,按順序交付所有事件,所以也不適合做耗時(shí)任務(wù),因?yàn)槎鄠€(gè)事件共用這一個(gè)后臺(tái)線程ASYNC
在子線程調(diào)用,總是開啟一個(gè)新的線程來(lái)調(diào)用,適用于做耗時(shí)任務(wù),比如數(shù)據(jù)庫(kù)操作,網(wǎng)絡(luò)請(qǐng)求等,不適合做計(jì)算任務(wù),會(huì)導(dǎo)致開啟大量線程
流程
register
獲得傳入對(duì)象的類對(duì)象沥曹。
-
獲得這個(gè)類中定義的訂閱函數(shù)。
subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//subscriberClass傳入對(duì)象的class-
從緩存中取出METHOD_CACHE訂閱方法集合茬高。如果有直接返回丽猬。
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
-
如果緩存中沒(méi)有,選擇合適的方法尋找訂閱方法熏瞄。
subscriberMethods = findUsingReflection(subscriberClass);直接通過(guò)反射查找
subscriberMethods = findUsingInfo(subscriberClass);默認(rèn)查找
兩者區(qū)別第二個(gè)多出從subscriberMethodFinder.subscriberInfoIndexes中獲取SubscriberInfoIndex來(lái)獲取SubscriberInfo從狀態(tài)池獲得一個(gè)狀態(tài)對(duì)象脚祟。
FindState findState = prepareFindState將訂閱者類傳入,設(shè)置一些狀態(tài)對(duì)象的參數(shù)强饮。
findState.initForSubscriber(subscriberClass);-
通過(guò)狀態(tài)對(duì)象尋找訂閱者信息由桌,如果找到就獲取到了訂閱方法數(shù)組,并循環(huán)檢測(cè)合法性邮丰,通過(guò)findState.subscriberMethods.add(subscriberMethod)放入其集合中行您。
// 尋找方法findState.subscriberInfo = getSubscriberInfo(findState); // 這一步就是多出來(lái)的通過(guò)subscriberMethodFinder.subscriberInfoIndexes的索引緩存查找
-
如果沒(méi)有沒(méi)有找到訂閱者信息,則調(diào)用方法柠座,用反射去尋找訂閱方法邑雅。
findUsingReflectionInSingleClass(findState);- 獲取訂閱類中定義的方法。(方法類型妈经、方法參數(shù)長(zhǎng)度之類)
- 遍歷方法集合淮野,檢測(cè)完合法性捧书,將合法的訂閱方法封裝,存入狀態(tài)對(duì)象
Class<?> eventType = parameterTypes[0] findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
狀態(tài)對(duì)象指向父類骤星,再次循環(huán)经瓷,找父類中的訂閱方法。
findState.moveToSuperclass();-
返回subscriberMethods洞难,并且回收f(shuō)indState
return getMethodsAndRelease(findState)
-
如果沒(méi)有找到訂閱方法舆吮,拋出異常程序崩潰。
如果找到了訂閱方法队贱,將它和訂閱者類對(duì)象組成鍵值對(duì)存儲(chǔ)到緩存METHOD_CACHE色冀。METHOD_CACHE.put(subscriberClass, subscriberMethods);
-
-
對(duì)每個(gè)訂閱函數(shù)進(jìn)行訂閱操作。
-
根據(jù)訂閱方法獲取事件類型柱嫌。
Class<?> eventType = subscriberMethod.eventType;
-
將訂閱者和訂閱方法組合成一個(gè)訂閱對(duì)象锋恬。
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
-
獲取訂閱對(duì)象集合,如果為空直接新建集合后放入编丘,
將訂閱對(duì)象集合中對(duì)象按優(yōu)先級(jí)排序后if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); 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++) { if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } }
-
根據(jù)注冊(cè)方法傳入的對(duì)象獲取到它可以相應(yīng)的事件類型集合与学,
如果沒(méi)有新建一個(gè)集合,將對(duì)象做key嘉抓,集合做value存Map typesBySubscriber當(dāng)中索守。
最后都會(huì)將事件類型存入集合//根據(jù)訂閱者獲取事件類型集合 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); //沒(méi)有存儲(chǔ)過(guò)事件類型,新建一個(gè)集合 if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } //put當(dāng)前事件類型進(jìn)去 subscribedEvents.add(eventType);
處理粘性事件抑片。如果之前有粘性事件卵佛,則取出并發(fā)送給訂閱者
-
post
使用ThreadLocal來(lái)存儲(chǔ)事件,他可以隔離多個(gè)線程對(duì)數(shù)據(jù)的訪問(wèn)沖突
-
獲得post線程狀態(tài)對(duì)象。
PostingThreadState postingState = currentPostingThreadState.get();
-
從這個(gè)線程狀態(tài)對(duì)象中取得事件隊(duì)列蓝丙。加入事件對(duì)象级遭。
List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event);
-
如果事件沒(méi)有在分發(fā)中,
設(shè)置分發(fā)狀態(tài)和是否主線程渺尘。
-
循環(huán)取出事件隊(duì)列中的事件進(jìn)行分發(fā)過(guò)程。
while (!eventQueue.isEmpty()) { postSingleEvent(eventQueue.remove(0), postingState); }
找到我們自定義事件類型的類對(duì)象说敏。
--->eventInheritance若為true鸥跟,會(huì)找到這個(gè)事件類型的自身和父類,逐一進(jìn)行事件分發(fā)盔沫。
--->eventInheritance為true医咨,只對(duì)自身事件類型進(jìn)行分發(fā)。
--->最終都會(huì)通過(guò)下面的postSingleEventForEventType分發(fā)subscriptionFound = postSingleEventForEventType(event, postingState, eventClass)
-
根據(jù)事件類型獲得訂閱對(duì)象集合架诞。
1. subscriptions = subscriptionsByEventType.get(eventClass);
-
如果集合不為空拟淮,循環(huán)subscriptions集合
將event和subscription給賦值postingState的屬性
調(diào)用postToSubscription(subscription, event, postingState.isMainThread);
賦值aborted = postingState.canceled;
然后重置postingState
postingState.event = null; postingState.subscription = null; postingState.canceled = false;
如果aborted = ture跳槽循環(huán)
-
根據(jù)threadMode找到合適的線程來(lái)調(diào)用訂閱函數(shù)而已
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { //根據(jù)訂閱方法注解中標(biāo)明的執(zhí)行線程執(zhí)行 switch (subscription.subscriberMethod.threadMode) { case POSTING: invokeSubscriber(subscription, event); break; case MAIN: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; case BACKGROUND: if (isMainThread) { 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); } }
**主線程mainThread: **
Poster:通過(guò)繼承Handler重寫handleMessage增加新的enqueue方法
enqueue方法:加入自己的隊(duì)列,發(fā)送空消息
handleMessage:invokeSubscriber(subscription, event)省略了很多邏輯
**backgroundPoster: **
enqueue方法:加入自己的隊(duì)列谴忧,如果第一次啟動(dòng)線程就傳入自己(實(shí)現(xiàn)了Runnable)然后啟動(dòng)線程
run方法:無(wú)限循環(huán)很泊,從隊(duì)列取pendingPost角虫,然后調(diào)用eventBus.invokeSubscriber(pendingPost)
**asyncPoster: **
enqueue方法:加入自己的隊(duì)列,啟動(dòng)線程傳入自己(實(shí)現(xiàn)了Runnable)
run方法:從隊(duì)列取pendingPost委造,然后調(diào)用eventBus.invokeSubscriber(pendingPost)
eventBus.invokeSubscriber(pendingPost):
method.invoke(subscription.subscriber, event):
-
返回flase
通過(guò)postToSubscription向訂閱者進(jìn)行事件分發(fā)戳鹅。
接下來(lái)調(diào)用postToSubscription繼續(xù)實(shí)際分發(fā)。
如果都沒(méi)有就發(fā)送沒(méi)有訂閱者的事件post(new NoSubscriberEvent(this, event));
-
-
重置postingState
postingState.isPosting = false; postingState.isMainThread = false;
unregister
根據(jù)傳入對(duì)象找到訂閱的事件類型集合昏兆,
for循環(huán)事件集合
從subscriptionsByEventType獲取subscriptions集合
如何subscription.subscriber == subscriber(傳入的對(duì)象)就從subscriptions集合移出
Rxbus
是基于Rxjava的一種封裝要比EventBus好枫虏,因?yàn)樾矢撸€程調(diào)度和鏈?zhǔn)絻?yōu)于Eventbus
ModuleBus
跟Eventbus類似爬虱,能傳遞基礎(chǔ)數(shù)據(jù)類型隶债。自定義的事件信息模型還是要添加到BaseModule中才能讓其他模塊引用
ModularizationArchitecture
是一個(gè)路由帶事件功能,已經(jīng)停工了跑筝,需要context燃异,使用場(chǎng)景有限,不多說(shuō)继蜡。
LocalRouter.getInstance()
組件化中使用總線怎么辦
可以抽離成一個(gè)單獨(dú)的模塊回俐,讓BaseModule依賴,把事件抽離到XXXBusModule稀并,來(lái)解耦仅颇,減少對(duì)BaseModule的影響。