所有入口均在EventBus.java中:
public void post(Object event)複製程式碼
public void register(Object subscriber)複製程式碼
public synchronized void unregister(Object subscriber) 複製程式碼
分析register
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();//獲取註冊物件的型別
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}複製程式碼
先來看findSubscriberMethods:
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//首先從快取中取出subscriberMethodss,如果有則直接返回該已取得的方法
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//從EventBusBuilder可知,ignoreGenerateIndex一般為false
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 {
//將獲取的subscriberMeyhods放入快取中
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}複製程式碼
上面程式碼的作用是查詢class是否有標識為觀察者的方法,首先從快取METHOD_CACHE中查詢,如果沒有再通過反射或者註解的方式來查詢。由於ignoreGeneratedIndex預設為false,所以預設是通過註解查詢。(當然也可以通過new EventBus(new EventBusBuilder().ignoreGeneratedIndex(true));)來設定用反射來查詢觀察方法。
所以以下著重看通過註解查詢的方法,即findUsingInfo
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//準備一個FindState,該FindState儲存了訂閱者類的資訊
FindState findState = prepareFindState();
//對FindState初始化
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//獲得訂閱者的資訊,一開始會返回null
findState.subscriberInfo = getSubscriberInfo(findState);
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 {
//1 、到了這裡
findUsingReflectionInSingleClass(findState);
}
//移動到父類繼續查詢
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}複製程式碼
最終會走到findUsingReflectionInSingleClass(findState);
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註解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
//引數型別 即為 事件型別
Class<?> eventType = parameterTypes[0];
// 2 、呼叫checkAdd方法
if (findState.checkAdd(method, eventType)) {
//從註解中提取threadMode
ThreadMode threadMode = subscribeAnnotation.threadMode();
//新建一個SubscriberMethod物件,並新增到findState的subscriberMethods這個集合內
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
//如果開啟了嚴格驗證,同時當前方法又有@Subscribe註解,對不符合要求的方法會丟擲異常
} 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");
}
}
}複製程式碼
這裡面的邏輯就是通過發射拿到class下所有的所有方法,然後遍歷所有方法,當方法入引數量為1,且含有Subscribe.class的註解時候,解析註解內容,儲存至findState.subscriberMethods中。
最終會回到return getMethodsAndRelease(findState);
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
//從findState獲取subscriberMethods,放進新的ArrayList
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
//把findState回收
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}複製程式碼
至此,SubscriberMethodFinder這個類走完了,回到EventBus#rigister
public void register(Object subscriber) {
new EventBus(new EventBusBuilder().ignoreGeneratedIndex(true));
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//繼續往下
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}複製程式碼
繼續看subscribe方法:
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
//將subscriber和subscriberMethod封裝成 Subscription
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//根據事件型別獲取特定的 Subscription,subscriptionsByEventType 是以event事件作為key,CopyOnWriteArrayList<Subscription>作為value的map,
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);
}
}
//根據優先順序來設定放進subscriptions的位置,優先順序高的會先被通知
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;
}
}
//根據subscriber(訂閱者)來獲取它的所有訂閱事件,以訂閱的類為value,類訂閱方法list作為value的map
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
//把訂閱者、事件放進typesBySubscriber這個Map中
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);
}
}
}複製程式碼
可以看到最終會儲存到2個map中去。
一個map是Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
另外一個是Map<Object, List<Class<?>>> typesBySubscriber;
subscriptionsByEventType是以event事件作為key,CopyOnWriteArrayList<Subscription>作為value的map,其中CopyOnWriteArrayList<Subscription>作用是儲存各個優先順序不同Subscription。
typesBySubscriber是以訂閱者及註冊類作為key,類訂閱方法list作為value的map。
至此,所有呼叫即已結束。
下面盜一張別人的圖來展示整個過程:
分析unRegister
public synchronized void unregister(Object subscriber) {
//根據當前的訂閱者來獲取它所訂閱的所有事件
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
//遍歷所有訂閱的事件
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
//從typesBySubscriber中移除該訂閱者
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}複製程式碼
上面呼叫了EventBus#unsubscribeByEventType,把訂閱者以及事件作為引數傳遞了進去,那麼應該是解除兩者的聯絡。
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//根據事件型別從subscriptionsByEventType中獲取相應的 subscriptions 集合
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
//遍歷所有的subscriptions,逐一移除
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}複製程式碼
可以看到,上面兩個方法的邏輯是非常清楚的,都是從typesBySubscriber或subscriptionsByEventType移除相應與訂閱者有關的資訊,登出流程相對於註冊流程簡單了很多,其實註冊流程主要邏輯集中於怎樣找到訂閱方法上。
分析post:
傳送事件呼叫:
EventBus.getDefault().post(new MessageEvent("Hello !....."));複製程式碼
/** Posts the given event to the event bus. */
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
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 {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}複製程式碼
其中currentPostingThreadState是
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};複製程式碼
為什麼需要用ThreadLoacl來儲存,目前還不清楚。(執行緒安全?)
ThreadLoacl儲存的PostingThreadState是如下結構
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<>();
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}複製程式碼
過程是先從執行緒中拿到PostingThreadState物件,並往PostingThreadState.eventQueued佇列中新增當前event事件。做一些是否狀態設定,然後最終呼叫postSingleEvent。
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
//該eventInheritance上面有提到,預設為true,即EventBus會考慮事件的繼承樹
//如果事件繼承自父類,那麼父類也會作為事件被髮送
if (eventInheritance) {
//查詢該事件的所有父類
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
//遍歷所有事件
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
//如果沒找到訂閱該事件的訂閱者
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}複製程式碼
可以看到會查詢event的所有父類,一起傳送給訂閱者。接著呼叫了
EventBus#postSingleEventForEventType
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//從subscriptionsByEventType獲取響應的subscriptions
subscriptions = subscriptionsByEventType.get(eventClass);
}
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;
}
//...
}
return true;
}
return false;
}複製程式碼
postToSubscription
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
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);
}
}複製程式碼
invokeSubscriber
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
}
//...
}複製程式碼
到目前為止,事件的傳送流程也講解完畢,為了方便理解,整個傳送流程也給出相應的流程圖:
結語
至此,EventBus的主要原始碼分析完畢。完成了訂閱、反訂閱、傳送及響應訊息的過程的原始碼細解析。
EventBus實質上是觀察者模式的實現,觀察者是訂閱類,被觀察者是Event事件,隨著Event事件發出或者改變時候,會通過EventBus通知訂閱類,然後通過發射呼叫訂閱類的方法。
核心資料是2個map,一個用來儲存所有Event事件所對應的註解和運算元據,一個用來儲存所有訂閱者所對應的方法資料。
核心流程就是貼出的2張圖。
核心方法包括反射和註解:
反射有2處:1、用於查詢訂閱類的所有需要通知的方法,2、用於呼叫訂閱類的訂閱方法。
註解:註解用於解析訂閱類的方法所包含的訂閱資訊(包括訂閱的執行緒、所訂閱的優先順序)。