1-注冊
1.1-核心
注冊主要原理就是EventBus的三個map變量的注冊:
- subscriptionsByEventType | EventType為key霉涨,Subscription列表為Value
- typesBySubscriber | 注冊對象subscriber為key,EventType列表為Value
- stickyEvents | EventType為key惭适,Event對象為Value
字段說明:
字段 | 說明 |
---|---|
EventType | 事件類型笙瑟,即@Subscribe注解的訂閱方法的第一個參數(shù)對應(yīng)的Class對象 |
Subscription | 封裝了訂閱對象subscriber及訂閱方法SubscriberMethod |
SubscriberMethod | 封裝了訂閱對象的訂閱方法的相關(guān)信息,即@Subscribe注解參數(shù)及注解的方法信息 |
subscriber | 注冊對象癞志,例如在MainActivty注冊即為MainActivity的實(shí)例對象 |
Event | 事件對象往枷,即@Subscribe注解的訂閱方法的第一個入?yún)?shí)參對象 |
1.2-注冊具體源碼
從EventBus.getDefault().register(this);
開始,this傳入的是當(dāng)前注冊類的Activity對象
/**
* EventBus.register方法
*/
public void register(Object subscriber) {
//@1.獲取對象類對應(yīng)的Class對象
Class<?> subscriberClass = subscriber.getClass();
//@2.通過反射獲取Class對象中注解的方法列表
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
//@5.遍歷獲取的目標(biāo)方法列表凄杯,并注冊
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
@2.findSubscriberMethods方法獲取Class對象中@Subscribe注解的方法列表错洁。subscriberMethodFinder是EventBus的成員變量具體實(shí)現(xiàn)
//SubscriberMethodFinder.findSubscriberMethods方法
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//先讀緩存
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//ignoreGeneratedIndex默認(rèn)為false,若自定義EventBusBuilder則為ture
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//@3.通過反射獲取Class文件的帶注解方法
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
//注冊類沒有@Subscriber注解,拋出異常
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;
}
}
@3.通過反射獲取Class文件的帶注解方法盾舌。
//SubscriberMethodFinder.findUsingInfo方法
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//通過FindState來輔助查找
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
//第一次注冊為null
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 {
//@4.篩選目標(biāo)方法墓臭,并將目標(biāo)方法相關(guān)信息封裝到findState中的集合
findUsingReflectionInSingleClass(findState);
}
//將findState.clazz修改為父類蘸鲸,到父類遍歷
findState.moveToSuperclass();
}
//返回findState中的SubscriberMethod列表妖谴,并釋放findState
return getMethodsAndRelease(findState);
}
@4.findUsingReflectionInSingleClass方法
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// 通過反射獲取Class對象的所有方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
。酌摇。膝舅。
}
//遍歷所有方法,根據(jù)條件篩選出目標(biāo)方法
for (Method method : methods) {
//獲取方法修飾符
int modifiers = method.getModifiers();
//方法是public且非abstract窑多、static等
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
//獲取方法的形參類型
Class<?>[] parameterTypes = method.getParameterTypes();
//只有一次參數(shù)
if (parameterTypes.length == 1) {
//獲取Subscribe注解類
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
//獲取訂閱事件的類型
Class<?> eventType = parameterTypes[0];
//判斷findState是否添加過該事件類型為key的鍵值對仍稀,未添加過返回true
if (findState.checkAdd(method, eventType)) {
//獲取注解中指定的線程
ThreadMode threadMode = subscribeAnnotation.threadMode();
//將訂閱方法、事件類型埂息、線程技潘、優(yōu)先級、是否支持粘性事件等封裝成SubscriberMethod
//并添加到findState的subscriberMethods集合中
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
千康。享幽。。
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
拾弃。值桩。。
}
}
}
@5.遍歷獲取的目標(biāo)方法列表豪椿,并注冊奔坟。主要是注冊三個map携栋。
//調(diào)用EventBus.subscribe方法注冊
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//獲取訂閱方法的事件類型
Class<?> eventType = subscriberMethod.eventType;
//將方法參數(shù)SubscriberMethod及注冊類Object封裝為Subscription
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//查找注冊類是否有對應(yīng)的Subscription列表
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
//沒有則創(chuàng)建集合 subscriptions
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();
//根據(jù)newSubscription的優(yōu)先級插入到subscriptions集合中
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
//判斷typesBySubscriber map中是否存在當(dāng)前注冊類的事件類型列表
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
//添加事件類型到列表
subscribedEvents.add(eventType);
//如果支持粘性事件
//1.4-粘性事件
if (subscriberMethod.sticky) {
。咳秉。婉支。
}
}
總結(jié)注冊流程:
- 1-根據(jù)反射獲取注冊類Class對象的所有方法
- 2-遍歷方法列表根據(jù)條件篩選目標(biāo)方法(public修飾一個形參,Subscribe注解)
- 3-將目標(biāo)方法信息及指定線程澜建、優(yōu)先級磅摹、粘性等封裝到SubscriberMethod。最終返回篩選出來的SubscriberMethod列表
-
4-遍歷SubscriberMethod列表霎奢,并分別注冊到EvnetBus的三個map集合中
圖1-注冊流程圖
2-取消注冊
EventBus.getDefault().unregister(this);
//EventBus.unregister方法
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
//遍歷注冊對象-eventType列表的map
for (Class<?> eventType : subscribedTypes) {
//@1
unsubscribeByEventType(subscriber, eventType);
}
//將該對象從map中移除
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
@1.調(diào)用unsbscribeByEventType將eventType-事件列表的map中移除目標(biāo)對象
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//通過EventType獲取對應(yīng)的事件列表
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
//依次刪除事件列表中與目標(biāo)對象一致的subscription
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
總結(jié)解注冊流程:
- 從object-eventType列表的map中遍歷eventType
- 獲取eventType對應(yīng)的事件列表subscriptions户誓,依次移除訂閱對象關(guān)聯(lián)的事件
- 將訂閱對象從object-eventType的map中移除
3-事件發(fā)送
EventBus.getDefault().post(new Object());
調(diào)用EventBus.post方法。在EventBus中維護(hù)一個PostingThreadState幕侠。各自線程維護(hù)一份帝美,保存了當(dāng)前線程的事件隊列,線程狀態(tài)晤硕,發(fā)送狀態(tài)悼潭,是否主線程等信息。
- ThreadLocal<PostingThreadState> currentPostingThreadState
final static class PostingThreadState {
//當(dāng)前線程的事件隊列
final List<Object> eventQueue = new ArrayList<>();
boolean isPosting;//是否發(fā)送狀態(tài)
boolean isMainThread;//是否主線程
Subscription subscription;//輔助記錄待通知的訂閱者
Object event;//輔助記錄待發(fā)送的事件
boolean canceled;
}
public void post(Object event) {
//獲取當(dāng)前線程的PostingThreadState
PostingThreadState postingState = currentPostingThreadState.get();
//獲取待發(fā)送事件隊列
List<Object> eventQueue = postingState.eventQueue;
//將當(dāng)前發(fā)送事件入列
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
//遍歷待發(fā)送事件列表
while (!eventQueue.isEmpty()) {
//@1發(fā)送單個事件
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
//重置postingState狀態(tài)
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
@1.逐一發(fā)送事件
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
//拿到該事件所有的父類事件類型
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
//遍歷事件類型
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
//@2查找訂閱者
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
//沒有訂閱
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
//發(fā)送NosubscriberEvent事件
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
@2.通過eventType-訂閱者列表找到對應(yīng)的訂閱者列表舞箍,依次發(fā)送事件到對應(yīng)的訂閱者
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//獲取eventType-訂閱者的map對應(yīng)的訂閱列表
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
//遍歷訂閱者Subscription
for (Subscription subscription : subscriptions) {
//記錄訂閱者及事件
postingState.event = event;
postingState.subscription = subscription;
boolean aborted;
try {
//@3發(fā)送事件到訂閱者
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
//清除PostingState狀態(tài)
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
@3.發(fā)送事件到對應(yīng)的訂閱者
舰褪。該模式下涉及到的三個列表:
- HandlerPoster mainThreadPoster;//切換到主線程執(zhí)行
- BackgroundPoster backgroundPoster;//切換到線程池執(zhí)行,有同步鎖
- AsyncPoster asyncPoster;//切換到線程池執(zhí)行疏橄,無同步鎖
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
//根據(jù)訂閱方法設(shè)置的線程模式執(zhí)行
switch (subscription.subscriberMethod.threadMode) {
//默認(rèn)線程模式占拍,在發(fā)送事件的線程接收事件
case POSTING:
//@4.通過反射執(zhí)行訂閱者的訂閱方法
invokeSubscriber(subscription, event);
break;
//指定主線程
case MAIN:
if (isMainThread) {//如果當(dāng)前是主線程則直接執(zhí)行
invokeSubscriber(subscription, event);
} else { //@5.否則子線程加入隊列,通過Handler切換到主線程執(zhí)行
mainThreadPoster.enqueue(subscription, event);
}
break;
//無論哪個線程都加入隊列捎迫,通過handler在主線程執(zhí)行
case MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
//后臺執(zhí)行
case BACKGROUND:
if (isMainThread) {//@7.主線程晃酒,加入隊列,通過線程池執(zhí)行
backgroundPoster.enqueue(subscription, event);
} else {//子線程窄绒,直接執(zhí)行
invokeSubscriber(subscription, event);
}
break;
//無論哪個線程都加入隊列贝次,線程池執(zhí)行
case ASYNC:
//@8.AsyncPoster與BackgroundPoster不同的是
//沒有加同步鎖
//每次執(zhí)行都會開一個子線程執(zhí)行
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
@4.通過反射執(zhí)行訂閱者類的訂閱方法
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);
}
}
@5.子線程加入隊列,通過Handler切換到主線程執(zhí)行
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) {
//將subscription和event封裝成PendingPost對象
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
//加入到隊列
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
//主線程Handler發(fā)送消息
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
//主線程Handler接收并處理消息
@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;
}
}
}
//@6.執(zhí)行事件
eventBus.invokeSubscriber(pendingPost);
彰导。蛔翅。。
}
} finally {
handlerActive = rescheduled;
}
}
}
@6.取出PendingPost并通過反射執(zhí)行訂閱方法
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
//是否PendingPost的引用資源
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
//通過反射調(diào)用對應(yīng)的方法位谋,此時在主線程執(zhí)行
invokeSubscriber(subscription, event);
}
}
@7.BACKGROUND線程模式下山析,主線程加入隊列,通過線程池切換到子線程執(zhí)行倔幼。BackgroundPoster原理和HandlerPoster類似盖腿。
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封裝subscription及event
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
//加入隊列
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
//調(diào)用newCachedThreadPool線程池,執(zhí)行任務(wù)
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;
}
}
}
//執(zhí)行訂閱事件
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
}
@8.ASYNC線程模式下,所有線程進(jìn)入隊列翩腐,通過線程池切換到子線程執(zhí)行鸟款。具體由AsyncPoster實(shí)現(xiàn),BackgroundPoster是通過CachedThreadPool來管理線程茂卦,而AsyncPoster則是有EventBusBuilder傳入的線程池來管理線程何什。且BackgroundPoster執(zhí)行時加了synchronized同步鎖,而AsyncPoster未加鎖等龙。
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);
//通過線程池切換到子線程執(zhí)行
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);
}
}
事件發(fā)送總結(jié):
- 1.將發(fā)送的事件保存在postingState中
- 2.遍歷postingState的事件列表eventQueue
-
3.遍歷eventQueue根據(jù)線程模式直接或間接通過反射執(zhí)行訂閱方法
事件發(fā)送流程圖
4-粘性事件
粘性事件使用:
//@1.訂閱處理粘性事件
@Subscribe(sticky = true)
public void testEventBust(Object obj) {
处渣。。蛛砰。
}
//@2.發(fā)送粘性事件
EventBus.getDefault().postSticky(new Object());
@1.訂閱處理粘性事件罐栈,當(dāng)sticky=true時,在EventBus.subscribe注冊方法中
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//見1-@5
泥畅。荠诬。。
if (subscriberMethod.sticky) {
if (eventInheritance) {
//遍歷stickyEvents集合
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();
//如果方法制成粘性事件位仁,則根據(jù)線程模式處理事件 checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
@2.發(fā)布粘性事件柑贞。
public void postSticky(Object event) {
// 將要發(fā)布的粘性事件存stickyEvents中
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// 普通的發(fā)布事件
post(event);
}
粘性事件總結(jié):
- 通過postSticky將粘性事件存儲到stickyEvents中
- 調(diào)用post發(fā)送粘性事件,若訂閱者活躍則會消耗該事件并從stickyEvents中移除
- 訂閱者注冊時聂抢,遍歷stickyEvents集合钧嘶,通過postToSubscription發(fā)送Event給當(dāng)前訂閱者并執(zhí)行