簡述
EventBus是一款針對Android優(yōu)化的發(fā)布/訂閱事件總線石蔗。主要功能是替代Intent,Handler,BroadCast在Fragment端铛,Activity尉剩,Service间坐,線程之間傳遞消息面粮。優(yōu)點(diǎn)是開銷小少孝,代碼更優(yōu)雅,以及將發(fā)送者和接收者解耦熬苍。
基本使用
1.新建一個類韭山,AnyEventType。可以是網(wǎng)絡(luò)請求返回的字符串钱磅,也可以是某個開關(guān)狀態(tài)梦裂,也可以是空。
public class AnyEventType {
public AnyEventType(){}
}
2.注冊訂閱者
EventBus.getDefault().register(this);
3.發(fā)送事件
EventBus.getDefault().post(new AnyEventType event);
4.編寫響應(yīng)事件訂閱方法
@Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true, priority = 100)
public void hello(String str) {
}
這里說明一下3.0之后可以通過@Subscribe注解,來確定運(yùn)行的線程threadMode,是否接受粘性事件sticky以及事件優(yōu)先級priority,而且方法名不在需要onEvent開頭,所以又簡潔靈活了不少.
5.解除注冊
EventBus.getDefault().unregister(this);
源碼解析
1.新建EventBus
-
默認(rèn)可通過靜態(tài)函數(shù) getDefault 獲取單例
public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); }}} return defaultInstance; }
-
EventBusBuilder 新建一個 EventBus
public static EventBusBuilder builder() { return new EventBusBuilder(); }
-
構(gòu)造函數(shù)新建一個EventBus
public EventBus() { this(DEFAULT_BUILDER); }
2.register
register 函數(shù)中會先根據(jù)訂閱者類名去subscriberMethodFinder
中查找當(dāng)前訂閱者所有事件響應(yīng)函數(shù)盖淡,然后循環(huán)每一個事件響應(yīng)函數(shù)年柠,依次執(zhí)行subscribe 函數(shù)
public void register(Object subscriber) {
subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
3.subscribe
源碼太長就不全部貼出來了
1.首先通過subscriptionsByEventType得到該事件類型所有訂閱者信息隊(duì)列,根據(jù)優(yōu)先級將當(dāng)前訂閱者信息插入到訂閱者隊(duì)列subscriptionsByEventType中褪迟;如果添加過就拋出異常冗恨。
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
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);
}
}
2.在typesBySubscriber中得到當(dāng)前訂閱者訂閱的所有事件隊(duì)列,將此事件保存到隊(duì)列typesBySubscriber中味赃,用于后續(xù)取消訂閱掀抹;
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
3.檢查這個事件是否是 Sticky 事件,如果是則立即分發(fā)sticky事件
if (subscriberMethod.sticky) {
//eventInheritance 表示是否分發(fā)訂閱了響應(yīng)事件類父類事件的方法
if (eventInheritance) {
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);
}
}
4.post
首先得到當(dāng)前線程的 post 信息PostingThreadState心俗,其中包含事件隊(duì)列傲武,將當(dāng)前事件添加到其事件隊(duì)列中,然后循環(huán)調(diào)用postSingleEvent 函數(shù)發(fā)布隊(duì)列中的每個事件城榛。
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
} try {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
postToSubscription 函數(shù)中會判斷訂閱者的 ThreadMode揪利,從而決定在什么 Mode 下執(zhí)行事件響應(yīng)函數(shù)。ThreadMode 共有四類:
- PostThread:默認(rèn)的 ThreadMode狠持,表示在執(zhí)行 Post 操作的線程直接調(diào)用訂閱者的事件響應(yīng)方法疟位,不論該線程是否為主線程(UI 線程)。當(dāng)該線程為主線程時喘垂,響應(yīng)方法中不能有耗時操作甜刻,否則有卡主線程的風(fēng)險。適用場景:對于是否在主線程執(zhí)行無要求正勒,但若 Post 線程為主線程得院,不能耗時的操作;
- MainThread:在主線程中執(zhí)行響應(yīng)方法昭齐。如果發(fā)布線程就是主線程,則直接調(diào)用訂閱者的事件響應(yīng)方法矾柜,否則通過主線程的 Handler 發(fā)送消息在主線程中處理——調(diào)用訂閱者的事件響應(yīng)函數(shù)阱驾。顯然,MainThread類的方法也不能有耗時操作怪蔑,以避免卡主線程里覆。適用場景:必須在主線程執(zhí)行的操作;
- BackgroundThread:在后臺線程中執(zhí)行響應(yīng)方法缆瓣。如果發(fā)布線程不是主線程喧枷,則直接調(diào)用訂閱者的事件響應(yīng)函數(shù),否則啟動唯一的后臺線程去處理。由于后臺線程是唯一的隧甚,當(dāng)事件超過一個的時候车荔,它們會被放在隊(duì)列中依次執(zhí)行,因此該類響應(yīng)方法雖然沒有PostThread類和MainThread類方法對性能敏感戚扳,但最好不要有重度耗時的操作或太頻繁的輕度耗時操作忧便,以造成其他操作等待。適用場景:操作輕微耗時且不會過于頻繁帽借,即一般的耗時操作都可以放在這里珠增;
- Async:不論發(fā)布線程是否為主線程,都使用一個空閑線程來處理砍艾。和BackgroundThread不同的是蒂教,Async類的所有線程是相互獨(dú)立的,因此不會出現(xiàn)卡線程的問題脆荷。適用場景:長耗時操作凝垛,例如網(wǎng)絡(luò)訪問。
5.unregister
通過typesBySubscriber來取出這個subscriber訂閱者訂閱的事件類型,從typesBySubscriber移除subscriber简烘。
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}