1.注冊
使用EventBus的第一步就是需要給當(dāng)前的Activiy注冊,注冊方式如下
EventBus.getDefault().register(this);
直接看register里面的方法
private synchronized void register(Object subscriber, boolean sticky, int priority) {
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod, sticky, priority);
}
}
這里首先調(diào)用了findSubscriberMethods方法 ,我們看下這個方法里面究竟干了什么
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
String key = subscriberClass.getName();
List<SubscriberMethod> subscriberMethods;
synchronized (methodCache) {
subscriberMethods = methodCache.get(key);
}
if (subscriberMethods != null) {
return subscriberMethods;
}
...
while (clazz != null) {
...
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
String methodName = method.getName();
if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
...
Class<?> eventType = parameterTypes[0];
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(methodName);
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
if (eventTypesFound.add(methodKey)) {
// Only add if not already found in a sub class
subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
}
}
} else if (!skipMethodVerificationForClasses.containsKey(clazz)) {
Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "."
+ methodName);
}
}
}
clazz = clazz.getSuperclass();
}
...
}
這里我僅僅保留了與我們解析相關(guān)的代碼,可以看到這里主要是獲取我們注冊的Class里面onEvent方法,并將相關(guān)方法信息放入SubscriberMethod里面,同時存儲在一個List里面并返回,通過這個方法就可以獲取到注冊Class里面所有的onEvent方法。
接下來就是對每個獲取到的方法執(zhí)行subscribe方法,方法如下
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
Class<?> eventType = subscriberMethod.eventType;
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<Subscription>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
// subscriberMethod.method.setAccessible(true);
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || newSubscription.priority > subscriptions.get(i).priority) {
subscriptions.add(i, newSubscription);
break;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<Class<?>>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (sticky) {
Object stickyEvent;
synchronized (stickyEvents) {
stickyEvent = stickyEvents.get(eventType);
}
if (stickyEvent != null) {
// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
// --> Strange corner case, which we don't take care of here.
postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
}
}
}
這里做了幾件事情
-
這里通過className,method以及priority(優(yōu)先級)構(gòu)建Subscription
然后通過priority來將Subscription放到CopyOnWriteArrayList的安全線程list中,這個list保存在一個Map中,Map根據(jù)subscriberMethod.eventType來存儲list
而這個eventType是Class<?>,它是個通配泛型,?可以代表任何類型,我測試的類型如下
class com.xinyuanhxy.libreadprogejct.TestEvent當(dāng)然不同的類的類型也不同
所以當(dāng)不同類的onEvent是同一個Event類,則會加載在同一個List中存儲相關(guān)數(shù)據(jù)
通過subscriber即當(dāng)前類的名稱獲取list列表,并存儲上面的eventType,即建立class與Event類集合的map信息
-
如果該事件處理方法為粘性事件,即設(shè)置了“sticky = true”,則需要調(diào)用checkPostStickyEventToSubscription
判斷是否有粘性事件需要處理,如果需要處理則觸發(fā)一次事件處理函數(shù)這個和BroadCastReceiver中的stickyBroadCastReceiver類似
那么這里就將我們注冊相關(guān)的信息解析并存儲下來了,接下來就是發(fā)送消息相關(guān)了。
總結(jié)一下整個注冊過程,大致分為3步:
獲取注冊類的onEvent方法,存儲相關(guān)信息
建立Event類與相關(guān)onEvent方法類的map信息,與建立class與Event類集合的map信息
處理粘性事件
2.發(fā)送消息與接收消息相關(guān)
發(fā)送消息如下
EventBus.getDefault().post(new TestEvent());
直接看post里面的方法
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;
}
}
}
currentPostingThreadState是一個ThreadLocal類型,里面存儲了PostingThreadState,PostingThreadState包含了一個事件隊列eventQueue和一些標(biāo)志信息。eventQueue存放所有待post的事件對象。
接下來會調(diào)用postSingleEvent方法post該事件
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);
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));
}
}
}
如果允許事件繼承,則會調(diào)用lookupAllEventTypes查找所有的父類和接口類。并將其保存到eventTypesCache中,方便下次使用。
接下來調(diào)用postSingleEventForEventType方法,如下
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
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;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
這里就是根據(jù)eventClass為key從subscriptionsByEventType對象中獲取Subscription列表。在上面講register的時候我們已經(jīng)看到EventBus在register的時候會將Subscription列表存儲在subscriptionsByEventType中。接下來會遍歷subscriptions列表然后調(diào)用postToSubscription方法進(jìn)行下一步處理。
最后調(diào)用到invokeSubscriber方法,如下
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);
}
}
這里通過反射調(diào)用相應(yīng)的onEvent()方法,接下來就會執(zhí)行我們的處理邏輯了
到這里關(guān)于發(fā)送與接收就分析完了,
總結(jié)一下整個post過程,大致分為3步:
將事件對象添加到事件隊列eventQueue中等待處理
遍歷eventQueue隊列中的事件對象并調(diào)用postSingleEvent處理每個事件
找出訂閱過該事件的所有事件處理函數(shù),并在相應(yīng)的線程中執(zhí)行該事件處理函數(shù)
3.取消事件注冊
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
將register過程注冊到EventBus的事件處理函數(shù)移除掉。