一、Event的注册
使用方式:
EventBus.getDefault().register(this);
所做的事情:
- 保存当前订阅类所订阅的所有事件类型,保存每种事件类型对应的Subscription列表。
//Key为订阅类,Value为事件类型列表。
private final Map<Object, List<Class<?>>> typesBySubscriber;
//Key为事件类型的Class实例,Value为订阅该事件的所有Subscription列表。
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
- 使用Subscription类封装订阅者(Object)和订阅方法(SubscriberMethod),将该Subscription对象插入到当前事件类型对应的CopyOnWriteArrayList<Subscription>中,并且按照subscriberMethod.priority由高到低排序;
- 将当前事件类型插入到当前订阅类的事件类型列表中。
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
![](https://img.haomeiwen.com/i6351695/a642614b23cabdaf.png)
二、查找订阅类的所有订阅方法
1. 查找方法
通过反射查找订阅方法,需要满足以下条件:
- public且非static、非abstract的方法;
- 只有一个参数;
- 注解类型为Subscribe;
2. 订阅方法的保存
使用SubscriberMethod类保存,设计为:
public class SubscriberMethod {
final Method method; //订阅方法的Method实例
final ThreadMode threadMode; //线程模式
final Class<?> eventType; //传递的消息类型,也即订阅方法的参数类型;
final int priority;
final boolean sticky;
/** Used for efficient comparison */
String methodString;
public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
this.method = method;
this.threadMode = threadMode;
this.eventType = eventType;
this.priority = priority;
this.sticky = sticky;
}
...
}
3. 查找状态的保存
使用FindState类,设计为:
static class FindState {
//订阅方法列表
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
//订阅方法的参数类型Class<?> --> 订阅方法Method实例;
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
//订阅方法的函数签名:<方法名称> + ">" + <参数类型名> --> 订阅类的Class实例.
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
void recycle();
//添加
boolean checkAdd(Method method, Class<?> eventType);
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType);
void moveToSuperclass();
}
class SubscriberMethodFinder {
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
...
} else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
/**
* 通过反射查找订阅方法,需要满足以下条件:
* 1. public且非static、非abstract的方法;
* 2. 只有一个参数;
* 3. 注解类型为Subscribe;
* @param 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 subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
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");
}
}
}
}
4. 查找和存储过程:
(1)查第1个HashMap:
final Map<Class, Object> anyMethodByEventType;
其中,Key为EventType1对象的Class实例;Value为订阅方法的Method实例。
(2)若(1)中已存在相同的Key值,则查第2个HashMap:
final Map<String, Class> subscriberClassByMethodKey;
其中,Key为订阅方法的签名信息,格式:
<methodName> + “>” + <eventType1ClassName>
Value为订阅方法所在类的Class实例。
分几种情况来考虑
(1)当前类有两个及以上不同名的方法订阅EventType1:
结果:
所有不同的订阅方法都有效,均保存在第2个的HashMap中;
(2)当前类有方法订阅EventType1,父类也有同名的方法订阅EventType1:
结果:
父类的同名订阅方法被覆盖,无效;使用当前类的同名方法。
(3)当前类有方法订阅EventType1,父类也有不同名的方法订阅EventType1:
结果:
父类和当前类的订阅方法都有效。
下面详细分析一下第(1)种情况的实现流程:
- 找到第1个订阅的方法,插入Key-Value对 {Class<EventType1>, 方法1的Method实例} 到第1个HashMap中,checkAdd()方法返回true,表示插入成功;
- 找到第2个订阅方法,插入Key-Value对 {Class<EventType1>,方法2的Method实例},因为已经存在相同的Key值,所以开始使用第2个HashMap。
① 取出第1个HashMap的Key为Class<EventType1>的Value。
--> 若是Method实例:
将该Method实例是第1个订阅方法插入的,先将其插入到第2个HashMap中;若插入失败,抛出IllegalStateException异常;若插入成功,则进入步骤2;
--> 若不是Method实例,直接进入步骤3;
② 插入{Class<EventType>, 非Method实例},将原来的 {Class<EventType>,Method实例} 破坏掉;
③ 将第2个订阅方法插入到第2个HashMap中。
完整的源码如下:
static class FindState {
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
//<methodName> + ">" + <eventTypeName> -> method所在的类的Class.
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
void recycle() {
subscriberMethods.clear();
anyMethodByEventType.clear();
subscriberClassByMethodKey.clear();
methodKeyBuilder.setLength(0);
subscriberClass = null;
clazz = null;
skipSuperClasses = false;
subscriberInfo = null;
}
boolean checkAdd(Method method, Class<?> eventType) {
// 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
// Usually a subscriber doesn't have methods listening to the same event type.
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
Class<?> methodClass = method.getDeclaringClass();
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
return true;
} else {
// Revert the put, old class is further down the class hierarchy
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** Skip system classes, this just degrades performance. */
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
}
三、消息的发布和订阅
发布的状态使用PostingThreadState描述,
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<Object>(); //等待处理的事件
boolean isPosting;
boolean isMainThread; //post()操作是否位于主线程
Subscription subscription;
Object event;
boolean canceled;
}
/**
* 查找HashMap,获取该事件类型对应的Subscriptions列表。
* 结束后PostingThreadState的event和subscription置为null, canceled置为false.
*/
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;
}
四、消息传递的拦截
仅限于ThreadMode.POSTING模式,在处理事件的方法中调用,后面的事件传送会被取消,即后面的调阅方法将收不到该事件。
public void cancelEventDelivery(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
//注意:只有当postingState.isPosting为true,即在post的过程中(已开始post,订阅者们还未全部收到)才有效。
if (!postingState.isPosting) {
throw new EventBusException(
"This method may only be called from inside event handling methods on the posting thread");
} else if (event == null) {
throw new EventBusException("Event may not be null");
} else if (postingState.event != event) {
throw new EventBusException("Only the currently handled event may be aborted");
} else if (postingState.subscription.subscriberMethod.threadMode != ThreadMode.POSTING) {
throw new EventBusException(" event handlers may only abort the incoming event");
}
postingState.canceled = true;
}
网友评论