一、Subscribe注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
/**
* 订阅方法的线程模式 默认是POSTING
* @return
*/
ThreadMode threadMode() default ThreadMode.POSTING;
/**
* 是否是粘性事件 默认false
*/
boolean sticky() default false;
/**
* 是否有优先级
* 指定事件订阅方法的优先级,默认为0,如果多个事件订阅方法可以接收相同事件的,则优先级高的先接收到事件
* @return
*/
int priority() default 0;
}
public enum ThreadMode {
/**
*默认的线程模式,在那个线程发送事件就在对应线程处理事件,避免了线程切换,效率高
*/
POSTING,
/**
*主线程(UI线程)发送事件,则直接在主线程处理事件;如果在子线程发送事件,则先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。
*/
MAIN,
/**
*无论在那个线程发送事件,都先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。
*/
MAIN_ORDERED,
/**
* 如果在主线程发送事件,则先将事件入队列,然后通过线程池依次处理事件;如果在子线程发送事件,则直接在发送事件的线程处理事件。
*/
BACKGROUND,
/**
* 无论在那个线程发送事件,都将事件入队列,然后通过线程池处理。
*/
ASYNC
}
二、注册事件订阅方法
EventBus.getDefault().register(this);
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) {
//METHOD_CACHE 保存订阅类及其所有的订阅方法SubscriberMethod ,提高效率
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//使用默认的EventBusBuilder 默认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 {
//保存以类为key,方法集合为value到Map中
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
findUsingInfo
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//初始化 FindState
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
//findState.clazz就是订阅类
while (findState.clazz != null) {
//findState.subscriberInfo == 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 {
//通过反射查找
findUsingReflectionInSingleClass(findState);
}
// 修改findState.clazz为subscriberClass的父类Class,即需要遍历父类
findState.moveToSuperclass();
}
// 查找到的方法保存在了FindState实例的subscriberMethods集合中。
// 使用subscriberMethods构建一个新的List<SubscriberMethod>
// 释放掉findState
return getMethodsAndRelease(findState);
}
findUsingReflectionInSingleClass
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();
// 如果是public类型,但非abstract、static等
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
// 获得当前方法所有参数的类型
Class<?>[] parameterTypes = method.getParameterTypes();
// 如果当前方法只有一个参数
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
// 如果当前方法使用了Subscribe注解
if (subscribeAnnotation != null) {
// 得到该参数的类型
Class<?> eventType = parameterTypes[0];
// checkAdd()方法用来判断FindState的anyMethodByEventType map是否已经添加过以当前eventType为key的键值对,没添加过则返回true
if (findState.checkAdd(method, eventType)) {
// 得到Subscribe注解的threadMode属性值,即线程模式
ThreadMode threadMode = subscribeAnnotation.threadMode();
// 创建一个SubscriberMethod对象,并添加到subscriberMethods集合
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} 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");
}
}
}
subscribe
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//得到方法的事件类型
Class<?> eventType = subscriberMethod.eventType;
//将订阅类 和 订阅的方法保存到Subscription中
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//从subscriptionsByEventType中查找是否存在,不存在保存进去。存在说明已经注册过了
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);
}
}
//循环遍历所有方法 把优先级这个属性大小进行排序
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;
}
}
//根据订阅类查找类中所有的订阅事件,如果不存在新建订阅事件集合。并将订阅事件添加进去
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
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);
}
}
}
三、取消注册
取消注册就非常简单了。移除typesBySubscriber 和subscriptionsByEventType对应的订阅属性
public synchronized void unregister(Object subscriber) {
//根据订阅类获取该类中的所有订阅事件
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
// 遍历参数类型集合,释放之前缓存的当前类中的Subscription
unsubscribeByEventType(subscriber, eventType);
}
//移除该类对应的事件集合
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//根据订阅类型得到所有的Subscription
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
//循环当前的集合 移除集合中该订阅类
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
四、发送事件
将要发送的事件保存到事件队列里面,然后遍历事件队列,查找事件类型对应的Subscription,
public void post(Object event) {
// currentPostingThreadState是一个PostingThreadState类型的ThreadLocal
// PostingThreadState类保存了事件队列和线程模式等信息
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
//要发送的事件添加到事件队列里面
eventQueue.add(event);
// isPosting默认为false
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;
}
}
}
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
// eventInheritance默认为true,表示是否向上查找事件的父类
if (eventInheritance) {
// 查找当前事件类型的Class,将当前事件类型的Class保存到集合
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
// 遍历Class集合,继续处理事件-------------------------
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);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
// 获取事件类型对应的Subscription集合
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
//设置PostingThreadState 保存的事件状态和方法
postingState.event = event;
postingState.subscription = subscription;
boolean aborted;
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;
}
处理事件
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 {
// 如果是在子线程发送事件,则将事件入队列,通过Handler切换到主线程执行处理事件
//HandlerPoster 先入队列
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
// 无论在那个线程发送事件,都先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
// 如果在主线程发送事件,则先将事件入队列,然后通过线程池依次处理事件
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
// 如果在子线程发送事件,则直接在发送事件的线程通过反射处理事件
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
// 将事件入队列,然后通过线程池处理。AsyncPoster
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
六.粘性事件
先发送事件,后续再准备订阅事件的方法、注册事件
public void postSticky(Object event) {
//保存到Map中
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
//发送事件
post(event);
}
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
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, isMainThread());
}
}