文章目录
1 两个Map
首先理解EventBus中两个HashMap对象的用途。
1 subscriptionsByEventType
表示同一个事件被多少个订阅者订阅
用途:
1 通过事件类型,找到所有的订阅者,然后将此事件发送给所有的订阅者。
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
例如FirstActivity中订阅EventA事件
FirstActivity#onEventMainThread()
public void onEventMainThread(EventA eventA) {}
SecondActivity中也订阅了EventA事件
SecondActivity#onEventMainThread()
public void onEventMainThread(EventA eventA) {}
那么此时 Map<Class<?>, CopyOnWriteArrayList> 中key为EventA.class,value为FirstActivity和SecondActivity构成的集合
2 typesBySubscriber
表示同一个类订阅了多少个方法
用处:
1 当订阅者取消订阅时,移除当前订阅者的所有事件
2 判断当前类是否订阅了某个事件
private final Map<Object, List<Class<?>>> typesBySubscriber;
例如FirstActivity中订阅了两个方法
FirstActivity#onEventMainThread()
public void onEventMainThread(EventA eventA) {}
public void onEventMainThread(EventB eventB) {}
此时Map<Object, List<Class<?>>>的其中一个元素的key为FirstActivity实例,value为EventA与EventB构成的集合
2 订阅过程
订阅者通过register()方法来完成订阅
private synchronized void register(Object subscriber, boolean sticky, int priority) {
//1 通过subscriberMethodFinder来找到当前类的所有订阅方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
//2 遍历所有订阅方法,添加到typesBySubscriber和subscriptionsByEventType中
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod, sticky, priority);
}
}
1 封装并获取SubscriberMethod集合
通过反射来遍历当前类的所有订阅方法,并把订阅的方法封装为SubscriberMethod对象
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
Class<?> clazz = subscriberClass;
HashSet<String> eventTypesFound = new HashSet<String>();
StringBuilder methodKeyBuilder = new StringBuilder();
while (clazz != null) {
String name = clazz.getName();
if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
// Skip system classes, this just degrades performance
break;
}
// 1 通过反射拿到订阅者中所有的方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
String methodName = method.getName();
if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {
int modifiers = method.getModifiers();
//2 订阅方法的事件类型参数
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
//3 根据方法名来获得该方法执行的线程
ThreadMode threadMode;
if (modifierString.length() == 0) {
threadMode = ThreadMode.PostThread;
} else if (modifierString.equals("MainThread")) {
threadMode = ThreadMode.MainThread;
} else if (modifierString.equals("BackgroundThread")) {
threadMode = ThreadMode.BackgroundThread;
} else if (modifierString.equals("Async")) {
threadMode = ThreadMode.Async;
} else {
if (skipMethodVerificationForClasses.containsKey(clazz)) {
continue;
} else {
throw new EventBusException("Illegal onEvent method, check for typos: " + method);
}
}
Class<?> eventType = parameterTypes[0];
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(methodName);
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
if (eventTypesFound.add(methodKey)) {
//4 将method threadMode eventType封装成SubscriberMethod对象
subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
}
}
}
}
clazz = clazz.getSuperclass();
}
return subscriberMethods;
}
2 添加到订阅者集合中
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
//1 将事件添加到 subscriptionsByEventType中
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;
}
}
//2 将事件添加到typesBySubscriber中
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<Class<?>>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
}
3 总结:
1 首先通过SubscriberMethodFinder中的findSubscriberMethods()方法来遍历当前类中所有的的事件接收方法
2 并将这些方法封装为SubscriberMethod对象,SubscriberMethod对象主要又三个参数构成
final Method method; // 事件接收方法
final ThreadMode threadMode; //事件被执行的线程
final Class<?> eventType; //事件类型
3 由于一个类可以订阅多个事件,所以findSubscriberMethods()方法返回的是SubscriberMethod对象集合
4 遍历SubscriberMethod集合,并将转换为Subscription对象
Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
Subscription(Object subscriber, SubscriberMethod subscriberMethod, int priority) {
this.subscriber = subscriber; //订阅者
this.subscriberMethod = subscriberMethod; //包含事件类型,和其他参数的SubscriberMethod对象
this.priority = priority;
active = true;
}
5 将Subscription添加到subscriptionsByEventType和typesBySubscriber中
6 subscriptionsByEventType是HashMap类型,Key为事件类(Event),Value为订阅者集合(CopyOnWriteArrayList>)
表示的是一个事件被多少个订阅者订阅,
7 typesBySubscriber同为HashMap类型,Key订阅者类型(例如Activity),Value订阅的事件集合(List<Event.class>)
3 发送事件过程
1 发送事件调用栈
1 触发发送一个事件
public void onClickStart(View view) {
EventBus.getDefault().post(new EventA("message from SecondActivity"));
}
2 通过调用postSingleEvent()发送事件
EventBus#post()
public void post(Object event) {
//用于标识当前线程是否正在发送
PostingThreadState postingState = currentPostingThreadState.get();
//获取当前执行的线程
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
}
3 继续调用postSingleEvent()
EventBus#postSingleEvent()
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
//如果父类也订阅了同样的的事件,则将这些事件添加到集合中
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);
}
}
4 调用postSingleEventForEventType();
EventBus#postSingleEventForEventType();
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
//通过映射的map,获取所有的订阅者
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
//遍历所有的订阅者
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 false;
}
5 根据线程判断反射调用具体在哪个线程中执行
EventBus#postToSubscription()
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case PostThread:
invokeSubscriber(subscription, event);
break;
case MainThread:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BackgroundThread:
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);
}
}
6 当订阅者接收事件的线程和当前线程相同时 则直接通过反射来调用订阅者接收事件的方法
EventBus#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);
}
}
2 事件执行的线程
在postToSubscription方法中,会根据订阅事件执行的线程来决定在哪个线程中执行事件的接收方法
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case PostThread: //订阅事件执行线程和当前线程相同
invokeSubscriber(subscription, event);
break;
case MainThread:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BackgroundThread: //订阅事件在后台线程执行,如果当前线程在非主线程,则直接执行订阅方法,如果不在主线程,则将此事件添加到队列中,并通过线程池来执行
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);
}
}