簡(jiǎn)述
EventBus是一款針對(duì)Android優(yōu)化的發(fā)布/訂閱事件總線。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,線程之間傳遞消息。優(yōu)點(diǎn)是開銷小,代碼更優(yōu)雅,以及將發(fā)送者和接收者解耦。
基本使用
1.新建一個(gè)類,AnyEventType。可以是網(wǎng)絡(luò)請(qǐng)求返回的字符串,也可以是某個(gè)開關(guān)狀態(tài),也可以是空。
public class AnyEventType {
public AnyEventType(){}
}
2.注冊(cè)訂閱者
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)先級(jí)priority,而且方法名不在需要onEvent開頭,所以又簡(jiǎn)潔靈活了不少.
5.解除注冊(cè)
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 新建一個(gè) EventBus
public static EventBusBuilder builder() { return new EventBusBuilder(); }
-
構(gòu)造函數(shù)新建一個(gè)EventBus
public EventBus() { this(DEFAULT_BUILDER); }
2.register
register 函數(shù)中會(huì)先根據(jù)訂閱者類名去subscriberMethodFinder
中查找當(dāng)前訂閱者所有事件響應(yīng)函數(shù),然后循環(huán)每一個(gè)事件響應(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)先級(jí)將當(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.檢查這個(gè)事件是否是 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ì)列中的每個(gè)事件。
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ù)中會(huì)判斷訂閱者的 ThreadMode,從而決定在什么 Mode 下執(zhí)行事件響應(yīng)函數(shù)。ThreadMode 共有四類:
- PostThread:默認(rèn)的 ThreadMode,表示在執(zhí)行 Post 操作的線程直接調(diào)用訂閱者的事件響應(yīng)方法,不論該線程是否為主線程(UI 線程)。當(dāng)該線程為主線程時(shí),響應(yīng)方法中不能有耗時(shí)操作,否則有卡主線程的風(fēng)險(xiǎn)。適用場(chǎng)景:對(duì)于是否在主線程執(zhí)行無要求,但若 Post 線程為主線程,不能耗時(shí)的操作;
- MainThread:在主線程中執(zhí)行響應(yīng)方法。如果發(fā)布線程就是主線程,則直接調(diào)用訂閱者的事件響應(yīng)方法,否則通過主線程的 Handler 發(fā)送消息在主線程中處理——調(diào)用訂閱者的事件響應(yīng)函數(shù)。顯然,MainThread類的方法也不能有耗時(shí)操作,以避免卡主線程。適用場(chǎng)景:必須在主線程執(zhí)行的操作;
- BackgroundThread:在后臺(tái)線程中執(zhí)行響應(yīng)方法。如果發(fā)布線程不是主線程,則直接調(diào)用訂閱者的事件響應(yīng)函數(shù),否則啟動(dòng)唯一的后臺(tái)線程去處理。由于后臺(tái)線程是唯一的,當(dāng)事件超過一個(gè)的時(shí)候,它們會(huì)被放在隊(duì)列中依次執(zhí)行,因此該類響應(yīng)方法雖然沒有PostThread類和MainThread類方法對(duì)性能敏感,但最好不要有重度耗時(shí)的操作或太頻繁的輕度耗時(shí)操作,以造成其他操作等待。適用場(chǎng)景:操作輕微耗時(shí)且不會(huì)過于頻繁,即一般的耗時(shí)操作都可以放在這里;
- Async:不論發(fā)布線程是否為主線程,都使用一個(gè)空閑線程來處理。和BackgroundThread不同的是,Async類的所有線程是相互獨(dú)立的,因此不會(huì)出現(xiàn)卡線程的問題。適用場(chǎng)景:長耗時(shí)操作,例如網(wǎng)絡(luò)訪問。
5.unregister
通過typesBySubscriber來取出這個(gè)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());
}
}