1.注册
使用EventBus的第一步就是需要给当前的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);
}
}
这里首先调用了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();
}
...
}
这里我仅仅保留了与我们解析相关的代码,可以看到这里主要是获取我们注册的Class里面onEvent方法,并将相关方法信息放入SubscriberMethod里面,同时存储在一个List里面并返回,通过这个方法就可以获取到注册Class里面所有的onEvent方法。
接下来就是对每个获取到的方法执行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(优先级)构建Subscription
然后通过priority来将Subscription放到CopyOnWriteArrayList的安全线程list中,这个list保存在一个Map中,Map根据subscriberMethod.eventType来存储list
而这个eventType是Class<?>,它是个通配泛型,?可以代表任何类型,我测试的类型如下
class com.xinyuanhxy.libreadprogejct.TestEvent
当然不同的类的类型也不同
所以当不同类的onEvent是同一个Event类,则会加载在同一个List中存储相关数据
通过subscriber即当前类的名称获取list列表,并存储上面的eventType,即建立class与Event类集合的map信息
-
如果该事件处理方法为粘性事件,即设置了“sticky = true”,则需要调用checkPostStickyEventToSubscription
判断是否有粘性事件需要处理,如果需要处理则触发一次事件处理函数这个和BroadCastReceiver中的stickyBroadCastReceiver类似
那么这里就将我们注册相关的信息解析并存储下来了,接下来就是发送消息相关了。
总结一下整个注册过程,大致分为3步:
获取注册类的onEvent方法,存储相关信息
建立Event类与相关onEvent方法类的map信息,与建立class与Event类集合的map信息
处理粘性事件
2.发送消息与接收消息相关
发送消息如下
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和一些标志信息。eventQueue存放所有待post的事件对象。
接下来会调用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));
}
}
}
如果允许事件继承,则会调用lookupAllEventTypes查找所有的父类和接口类。并将其保存到eventTypesCache中,方便下次使用。
接下来调用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;
}
这里就是根据eventClass为key从subscriptionsByEventType对象中获取Subscription列表。在上面讲register的时候我们已经看到EventBus在register的时候会将Subscription列表存储在subscriptionsByEventType中。接下来会遍历subscriptions列表然后调用postToSubscription方法进行下一步处理。
最后调用到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);
}
}
这里通过反射调用相应的onEvent()方法,接下来就会执行我们的处理逻辑了
到这里关于发送与接收就分析完了,
总结一下整个post过程,大致分为3步:
将事件对象添加到事件队列eventQueue中等待处理
遍历eventQueue队列中的事件对象并调用postSingleEvent处理每个事件
找出订阅过该事件的所有事件处理函数,并在相应的线程中执行该事件处理函数
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的事件处理函数移除掉。