EventBus用法及解析
EventBus介紹:
!- EventBus主要是用來組件之間進(jìn)行信息傳遞的宝鼓,相對(duì)于接口回調(diào)的方式的話澜薄,EventBus是可以解耦兩個(gè)組件的赶诊,而接口回調(diào)潮模,需要傳遞一個(gè)接口對(duì)象到另一個(gè)組件罢绽,耦合度比較高宠互,而且如果在界面銷毀時(shí)處理不當(dāng),還有可能造成內(nèi)存泄漏椭坚,EventBus的另一個(gè)優(yōu)點(diǎn)就是使用非常方便予跌,API調(diào)用非常簡(jiǎn)單。
EventBus使用
-
添加依賴
compile 'org.greenrobot:eventbus:3.1.1'
-
在需要發(fā)送消息的地方善茎,添加如下代碼
EventBus.getDefault().post(messageEvent);
-
在需要接收到事件的組件中需要做如下處理
- 注冊(cè)EventBus券册;
EventBus.getDefault().register(this);
* 定義一個(gè)接收事件的方法;
@Subscribe(threadMode = ThreadMode.ASYNC, sticky = true)
public void onMessageEvent(MessageObject object) {
//執(zhí)行接收到事件的操作
}
這里有幾個(gè)點(diǎn)需要注意:
1. 必須要帶有@Subscibe 并且方法的參數(shù)只能為1個(gè) 垂涯,修飾的關(guān)鍵字只能為public
2. 可以指定線程烁焙,不指定默認(rèn)為發(fā)出事件的那個(gè)線程;
1.ThreadMode.ASYNC
2.ThreadMode.POSTING
3.ThreadMode.MAIN
4.ThreadMode.BackGround
3. 可以指定當(dāng)前接收的事件是否為粘性事件耕赘,正常事件發(fā)送時(shí)骄蝇,組件必須已經(jīng)注冊(cè),不然無法接收到事件鞠苟,而粘性事件的話乞榨,如果發(fā)送時(shí)組件沒有注冊(cè),也可以接收到事件(發(fā)送時(shí)必須通過PostSticky()而不是post 当娱, 會(huì)將該事件添加到Sticky事件集合)
* 在組件銷毀時(shí)吃既,取消注冊(cè);
EventBus.getDefault().unregister(this);
EventBus源碼解析
從上面的EventBus使用可以看出EventBus使用非常簡(jiǎn)單跨细,那么EventBus底層究竟是怎么做的鹦倚,我們可以一起學(xué)習(xí)下
-
EventBus注冊(cè)過程
EventBus首先需要調(diào)用getDefault()方法,那么我們 getDefault方法中究竟做了什么public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
可以看出只是通過單例模式構(gòu)造了一個(gè)EventBus對(duì)象冀惭,調(diào)用了EventBus()的構(gòu)造方法
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
logger = builder.getLogger(); //是否打印log
subscriptionsByEventType = new HashMap<>(); //
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}
構(gòu)造方法中需要傳入一個(gè)EventBusBuilder對(duì)象震叙,我們?cè)趃etDefault()時(shí)傳遞了一個(gè)DEFAULT_BUILDER
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
boolean logSubscriberExceptions = true;
boolean logNoSubscriberMessages = true;
boolean sendSubscriberExceptionEvent = true;
boolean sendNoSubscriberEvent = true;
boolean throwSubscriberException;
boolean eventInheritance = true;
boolean ignoreGeneratedIndex; // 查找方法策略
boolean strictMethodVerification;
ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
List<Class<?>> skipMethodVerificationForClasses;
List<SubscriberInfoIndex> subscriberInfoIndexes;
Logger logger;
MainThreadSupport mainThreadSupport;
EventBusBuilder() {
}
而DEFAULT_BUILDER只是一個(gè)默認(rèn)值得Builder對(duì)象 , 有的變量在后面的分析中會(huì)用到散休,也就是說EventBus在getDefault()時(shí)媒楼,只是通過雙重判斷構(gòu)造了一個(gè)EventBus單利對(duì)象,傳入一個(gè)具有默認(rèn)值得EventBusBuilder對(duì)象戚丸,接下來看register這個(gè)方法
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
在register時(shí)划址,我們傳遞了當(dāng)前類,然后通過findSubscriberMethods(subscriberClass)獲取當(dāng)前類的所有訂閱方法限府,再調(diào)用 subscribe(subscriber, subscriberMethod)這個(gè)方法夺颤,我們先看findSubscriberMethods(subscriberClass)做了什么事情;
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
1. 從緩存中獲取訂閱類中的訂閱方法胁勺,如果緩存中有就返回世澜,沒有那么就根據(jù)ignoreGeneratedIndex這個(gè)標(biāo)志位來確定查找方法的邏輯,而這個(gè)變量的值就是在EventBusBuilder()中定義的署穗,默認(rèn)值為false 也就是說默認(rèn)是走findUsingInfo(subscriberClass)這個(gè)方法的寥裂,這個(gè)方法是優(yōu)先使用索引方式查找訂閱方法嵌洼,如果為true是通過反射的方式獲取訂閱方法,找到之后會(huì)將方法加入到緩存封恰,下次取出的時(shí)候就不需要通過反射獲取咱台。
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//...
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
findUsingReflectionInSingleClass(findState);
}
}
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
通過findstate里面的subscriberInfo獲取里面的方法,如果這個(gè)屬性為空俭驮,那么就通過findUsingReflectionInSingleClass(findState)這個(gè)方法來獲取訂閱方法,這個(gè)屬性的值是通過構(gòu)建EventBus對(duì)象傳遞的屬性值春贸,我們通過getDefault()方式獲取的EventBus這個(gè)屬性就是null混萝,傳入Builder對(duì)象來使用EventBus也不常用,所以我也沒有進(jìn)行深入研究萍恕。
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
if (findState.(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMod e,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
獲取訂閱類聲明的所有方法; 然后對(duì)獲取到的方法全部遍歷一遍
獲取方法的修飾符:即方法前面的public逸嘀、private等關(guān)鍵字。
如果該類方法使用了@subscribe標(biāo)注允粤、方法中只有一個(gè)參數(shù)崭倘、且方法修飾符為public。 findState.checkAdd(method, eventType) 如果之前沒有存在過則返回true
判斷@Subscribe標(biāo)注中的threadMode對(duì)應(yīng)的值类垫,默認(rèn)模式ThreadMode.POSTING
創(chuàng)建一個(gè)SubscriberMethod對(duì)象司光,該對(duì)象很簡(jiǎn)單就是保存有方法、方法參數(shù)類型悉患、線程模式残家、訂閱的優(yōu)先級(jí)、sticky標(biāo)志位售躁。與Retrofit類似只是這里創(chuàng)建了一個(gè)SubscriberMethod對(duì)象坞淮。并將該對(duì)象添加到FindSate的List集合中。
這樣就完成了通過訂閱類獲取訂閱的所有方法的過程陪捷,接下來就是調(diào)用 subscribe(subscriber, subscriberMethod)回窘;
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
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);
}
}
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;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) {
if (eventInheritance) {
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
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);
}
}
}
獲取方法參數(shù)類型;注意:使用@Subscribe標(biāo)注的方法有且僅有一個(gè)參數(shù)
利用訂閱者對(duì)象及其事件處理方法構(gòu)建一個(gè)Subscription對(duì)象市袖,該對(duì)象存儲(chǔ)有Object啡直、SubscriberMethod對(duì)象
從subscriptionsByEventType集合中獲取當(dāng)前事件對(duì)應(yīng)的Subscription對(duì)象集合; 如果得到的集合為空則創(chuàng)建一個(gè) 這 樣的集合,并將剛創(chuàng)建的Subscription對(duì)象添加進(jìn)subscriptionsByEventType集合中凌盯;如果得到的集合不為空且 剛 創(chuàng)建的Subscription對(duì)象已經(jīng)存在該集合中則拋出異常付枫,即同一個(gè)對(duì)象不能注冊(cè)兩次!
將第二步創(chuàng)建的Subscription對(duì)象按照優(yōu)先級(jí)存入Subscription對(duì)象集合中驰怎,該集合中的元素都是按照優(yōu)先級(jí)從高到低存放.
以subscriber對(duì)象為鍵阐滩,從typesBySubscriber獲取該對(duì)象對(duì)應(yīng)的接收事件類型集合,沒有則創(chuàng)建一個(gè)這樣的集合县忌,然后當(dāng)前事件類型添加到該集合中掂榔,最后將整個(gè)集合添加進(jìn)typesBySubscriber集合中继效;有則直接添加到接收事件類型集合中;
該值默認(rèn)為false装获,除非在注冊(cè)事件方法時(shí)使用了如下的標(biāo)注@Subscribe(sticky = true)瑞信;那么就會(huì)執(zhí)行到這里。通過便利粘性事件Map集合找到對(duì)應(yīng)的方法穴豫,如果找到了粘性事件方法就會(huì)調(diào)用checkPostStickyEventToSubscription(newSubscription, stickyEvent)凡简,而這個(gè)方法內(nèi)部就是調(diào)用了EventBus.Post()這個(gè)方法。
接下來我們看他的Post過程
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get(); // 獲取到當(dāng)前線程的PostingThreadState
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event); // 將發(fā)送的事件加到當(dāng)前線程的事件隊(duì)列中
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread(); // 判斷是不是在UI線程
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;
}
}
}
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<>();
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
在Post方法中精肃,只是獲取到一個(gè)當(dāng)前線程的PostingThreadState秤涩,然后將事件添加到了事件隊(duì)列中,真正執(zhí)行post事件的還是通過 postSingleEvent(eventQueue.remove(0), postingState)
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); // 傳遞參數(shù)類型類的繼承的類司抱,以及所有接口
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); // 根據(jù)傳入?yún)?shù)的類型進(jìn)行查找所有的訂閱方法
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
在上面的方法中筐眷,只是找到所有的事件類的父類或者接口,并且通過postSingleEventForEventType(event, postingState, clazz)進(jìn)行處理习柠,根據(jù)處理結(jié)果判斷是否找到訂閱方法匀谣,沒有找到則根據(jù)是否需要打印log信息,打印log以及發(fā)送了一個(gè)沒有訂閱方法方法的事件
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
//...
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass); // subscriptionsByEventTypemap集合资溃,保存了發(fā)送的參數(shù)對(duì)應(yīng)的Class文件以及所有的事件處理者 武翎,這個(gè)方法是用來獲取所有訂閱了該改事件的處理者
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
獲取到了所有的事件處理者后就直接遍歷,調(diào)用 postToSubscription(subscription, event, postingState.isMainThread) 這個(gè)方法進(jìn)行處理
釋放對(duì)象中的資源
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING: // 在當(dāng)前發(fā)送的線程中執(zhí)行 肉拓, 不作處理
invokeSubscriber(subscription, event);
break;
case MAIN: // 在UI線程執(zhí)行后频,如果當(dāng)前是主線程,則直接不做處理 暖途,不是就通過mainThreadPoster 卑惜,post到主線程進(jìn)行處理
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED: // 相當(dāng)于主線程優(yōu)先,如果主線程的poster存在就在主線程執(zhí)行驻售,不然在當(dāng)前線程執(zhí)行
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND: // 在子線程中執(zhí)行露久,如果為主線程就通過backgroundPoster去執(zhí)行,否則在當(dāng)前線程執(zhí)行
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC: // 在子線程中執(zhí)行欺栗,通過asyncPoster執(zhí)行
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
根據(jù)當(dāng)前線程判斷以及需要執(zhí)行的線程判斷是在哪個(gè)線程執(zhí)行毫痕,如果不需要更改線程,則調(diào)用 invokeSubscriber(subscription, event) 迟几, 不然則通過每個(gè)線程的poster來執(zhí)行
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
new HandlerPoster(eventBus, looper, 10);
Object looperOrNull = getAndroidMainLooperOrNull(); // 獲取主線程的looper
return looperOrNull == null ? null :
new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
public class HandlerPoster extends Handler implements Poster {
private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}
我們可以看到mainThreadPoster其實(shí)就是一個(gè)綁定了主線程的looper對(duì)象的Handler 通過handleMessage將消息傳回主線程處理
final class BackgroundPoster implements Runnable, Poster {
private final PendingPostQueue queue;
private final EventBus eventBus;
private volatile boolean executorRunning;
BackgroundPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
@Override
public void run() {
try {
try {
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
}
BackgroundPoster內(nèi)部維護(hù)了一個(gè)消息隊(duì)列消请,執(zhí)行的時(shí)候從消息隊(duì)列中取出消息通過線程池進(jìn)行處理,而線程池是在EventBuilder中的參數(shù)类腮,在我們通過getDefault()傳入默認(rèn)的Builder時(shí)臊泰,其實(shí)已經(jīng)創(chuàng)建了一個(gè)默認(rèn)的線城池對(duì)象,某一時(shí)段內(nèi)BackgroundThread模式的事件都會(huì)在BackgroundPoster的run方法中排隊(duì)處理蚜枢,也就是說該時(shí)段內(nèi)的所有事件是在一個(gè)線程中排隊(duì)后串行執(zhí)行的(隊(duì)列中的事件處理完之后又有新的事件發(fā)布才會(huì)新開線程)
ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
創(chuàng)建一個(gè)線程池缸逃,根據(jù)需要?jiǎng)?chuàng)建新線程针饥,但當(dāng)它們可用時(shí),將重用先前構(gòu)建的線程需频。這些池通常會(huì)提高執(zhí)行許多短命異步任務(wù)的程序的性能丁眼。調(diào)用{@代碼Exc}將重用以前構(gòu)建的線程,如果可用的話昭殉。如果沒有現(xiàn)有線程可用苞七,則將創(chuàng)建新線程并將其添加到池中。未使用六十秒的線程會(huì)終止挪丢。因此莽鸭,一個(gè)空閑時(shí)間足夠長(zhǎng)的池不要消耗任何資源
class AsyncPoster implements Runnable, Poster {
private final PendingPostQueue queue;
private final EventBus eventBus;
AsyncPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
eventBus.getExecutorService().execute(this);
}
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
}
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
invokeSubscriber(subscription, event); // 最終還是執(zhí)行invokeSubscriber
}
}
AsyncPoster與BackgroundPoster類似 ,內(nèi)部維護(hù)了一個(gè)消息隊(duì)列吃靠,執(zhí)行的時(shí)候從消息隊(duì)列中取出消息通過線程池進(jìn)行處理,AsyncPoster同樣也是一個(gè)Runnable足淆,與Backgroundposter不同的是AsyncPoster并發(fā)度更高巢块,不是在一個(gè)線程中對(duì)隊(duì)列中的事件進(jìn)行串行處理,而是每一個(gè)新添加的任務(wù)都會(huì)在線程池中開辟一個(gè)新線程執(zhí)行
接下來看下invokeSubscriber(subscription, event)巧号,是如何處理事件的
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
可以看到是通過反射執(zhí)行subscriberMethod族奢,到此為止訂閱方法才被執(zhí)行
-
EventBus 取消注冊(cè)流程
public synchronized void unregister(Object subscriber) { List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); // 獲取到參數(shù)類型集合 if (subscribedTypes != null) { for (Class<?> eventType : subscribedTypes) { unsubscribeByEventType(subscriber, eventType); } typesBySubscriber.remove(subscriber); } else { logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } } 可以看出通過訂閱類獲取到該類所有訂閱方法的參數(shù)類型集合,遍歷集合調(diào)用 unsubscribeByEventType(subscriber, eventType)丹鸿,并且移除當(dāng)前類的訂閱信息 private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { int size = subscriptions.size(); for (int i = 0; i < size; i++) { Subscription subscription = subscriptions.get(i); if (subscription.subscriber == subscriber) { subscription.active = false; subscriptions.remove(i); i--; size--; } } } } final class Subscription { final Object subscriber; final SubscriberMethod subscriberMethod; /** * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions. */ volatile boolean active; Subscription(Object subscriber, SubscriberMethod subscriberMethod) { this.subscriber = subscriber; this.subscriberMethod = subscriberMethod; active = true; } @Override public boolean equals(Object other) { if (other instanceof Subscription) { Subscription otherSubscription = (Subscription) other; return subscriber == otherSubscription.subscriber && subscriberMethod.equals(otherSubscription.subscriberMethod); } else { return false; } } @Override public int hashCode() { return subscriber.hashCode() + subscriberMethod.methodString.hashCode(); } }
并且將保存的訂閱方法從集合中移除越走,這樣就完成了取消訂閱過程
到此為止EventBus源碼分析也到此結(jié)束,有的地方我也研究的不是很清楚靠欢,但是其實(shí)我們可以將它的流程看清楚廊敌,其實(shí)也很簡(jiǎn)單,就是注冊(cè)的時(shí)候找到注冊(cè)類內(nèi)的所有注冊(cè)方法门怪,形成一個(gè)一對(duì)多的映射關(guān)系骡澈,保存到集合中,再根據(jù)方法中的參數(shù)類型掷空,+ 方法名肋殴,與訂閱的類,也有一個(gè)映射關(guān)系坦弟,當(dāng)發(fā)送事件時(shí)护锤,就根據(jù)發(fā)送的事件參數(shù)類型,找到與之對(duì)應(yīng)的所有的類酿傍,并且獲取到每個(gè)類中訂閱該事件的方法信息烙懦,通過反射調(diào)用該方法就可以了。原理并不是很復(fù)雜拧粪。
遇到的問題 :
發(fā)送Int類型 接收失敗
: 由于反射Int參數(shù)類型反射獲取到的是它的包裝類類型修陡,而存入的時(shí)候沧侥,存入的是Int類型,所以接收不到
泛型被擦除
: 加入?yún)?shù)是List<> + 泛型 由于反射獲取的類型只會(huì)是List類型魄鸦,所以通過參數(shù)類型匹配時(shí)宴杀,會(huì)匹配所有的list類型的參數(shù)方法,而不會(huì)管集合的泛型