没看过EventBus用法的童鞋移驾到EventBus基础用法,现在来探索EventBus的源码。
EventBus构造方法
当要使用EventBus时,首先会调用EventBus.getDefault()
来获取EventBus实例。现在查看getDefuelt
方法做了什么,如下:
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
很明显这是一个单例模式,采用了双重检查模式(DCL)。接下来查看EventBus的构造方法做了什么:
/**
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
* central bus, consider {@link #getDefault()}.
*/
public EventBus() {
this(DEFAULT_BUILDER);
}
这里DEFAULT_BUILDER是默认的EventBusBuilder,用来构造EventBus:
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
this调用了EventBus的另外一个构造方法,如下:
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}
可以通过构造一个EventBusBuilder来对EventBus进行配置,这里采用了建造者模式。
订阅者注册
获取EventBus后,便可以将订阅者注册到EventBus中。下面来看下register方法:
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
* <p/>
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//1
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);//2
}
}
}
(1)查找订阅者的订阅方法
上面代码注释1处的findSubscriberMethods
方法找出一个SubscriberMethod的集合,也就是传进来的订阅者的所有方法,接下来遍历订阅者的订阅方法来完成订阅者的注册操作。可以看出regsiter方法做了两件事:一件事是查找订阅者的订阅方法,另一种是订阅者的注册。在SubscriberMethod类中,只要用来保存订阅者方法的Methed对象、线程模式、事件类型、优先级、是否是黏性事件等属性。下面就来查看findSubscriberMethods
方法,如下:
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);//1
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);//3
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);//2
return subscriberMethods;
}
}
上面代码注释1处从缓存中查找是否有订阅方法的集合,如果找到了就立马返回。如果缓存中没有,则根据ignoreGeneratedIndex属性中的值来选择采用何种方法来查找订阅方法的集合。ignoreGeneratedIndex属性表示是否忽略注解器生成的MyEventBusIndex。如何生成MyEventBusIndex类以及它的使用,可以参考官方分档,这里不再讲解了。ignoreGeneratedIndex的默认值是false,可以通过EventBusBuilder来设置它的值。在注释2处找到订阅方法的集合后,放入缓存,以免下次继续查找。我们在项目中经常通过EventBus单例模式来获取的EventBus对象,也就ignoreGeneratedIndex为false的情况,这种情况调用了注释3处的findUsingInfo方法:
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass){
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
whild(findState.clazz !=null){
findState.subsciberInfo = getSubscriberInfo(findState);//1
if(findState.subscriberInfo!=null){
SubscriberMethed[] array = findState.subscriberInfo.getSubscriberMethods();//2
for(SubscriberMethed subscriberMethod : array){
if(findState.checkAdd(subscriberMethod.method,subscriberMethod.eventType)){
findState.subscriberMethods.add(subscriberMethod);
}
}
}else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
上面代码注释1处通过getSubscriberInfo方法来获取订阅者信息。在我们开始查找订阅方法的时候并没有忽略注释器为我们生成的索引MyEventBusIndex。如果我们通过EventBusBuilder配置了MyEventBusIndex,便会获取subscriberInfo。注释2处调用subscriberInfo的getSubscriberMethods方法便可以得到订阅方法相关的信息。如果没有配置MyEventBusIndex,后再通过getMethodsAndRelease方法对findState做回收处理并返回订阅方法的List集合。默认情况下是没有配置MyEventBusIndex的,因此现在查看下findUsing-ReflectionInSingleClass方法的执行过程,所示:
private void findUsingRelfectionInSingleClass(FindState findState){
Method[] methods;
try{
methods = findState.clazz.getDeclaredMethods();//1
}catch{
methods = findState.clazz.getMethods();
findState..skipSupreClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
if((modidiers & Modifier.PUBLIC)!=0&&(modifiers & MODIFIERS_IGNORE)==0){
Class<?>[] = parameterTypes = method.getParameterTypes();
if(parameterTypes.length == 1 ){
Subscribe subscribeAnntation = method.getAnntaotion(Subscribe.class);
if(subscribeAnnotation != null){
Class<?> eventType = parameterTypes[0];
if(findState.checkAdd(method,eventType)){
ThreadMode = threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(new SuberciberMethod
(method,eventType,threadMode,subscribeAnntation.priority,subcribeAnnotation.sticky()));
}
}
}
}
}
}
上面代码注释1处通过反射来获取订阅者中所有的方法,并根据方法的类型、参数和注解来找到订阅方法。找到订阅方法后将订阅的相关信息保存到findState中。
 ;(2)订阅者的注册过程
 ;在查找完订阅方法以后便开始对所有的订阅方法进行注册。我们再回到register方法中,在哪里的注释2处调用subscribe方法来对订阅方法进行注册,所示:
private void subscribe(Object subscriber,SubscriberMethod subscricberMethod){
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber,SubscriberMethod);//1
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionByEventType.get(eventType);//2
if(subscriptions == null){
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType,subscriptions);
}else{
//判断订阅者是否已经被注册
if(subscriptions .comtains(newSubscription)){
throw new EventBusException("Subcriber"+subscriber.getClass() + "already registered to event "+eventType);
}
}
int size = subscriptions.size();
for (int i = 0; i = size; i++){
if(i ==size||subscriberMethod.priority > subscriprions.get(i).subscriberMethod.priority){
subscriptions.add(i,newSubscription );//3
break;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);//4
if(subscribedEvents == null){
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber,subecribedEvents);
}
; subscribedEvents.add(eventType);
if(subscriberMethod.sticky){
if(eventInheritance){
//粘性事件的处理
Set<Map.Entry<Class<?>>,Object> entries = stickyEvents.entrySet();
for(Set<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);
}
}
}
首先,上面代码注释1处根据subscriber(订阅者)和subscriberMethod(订阅方法)创建一个Subscription(订阅对象)。注释2处根据eventType(事件类型)获取Subscriptions(订阅对象集合)。如果Subscriptions为null则重新创建,并将Subscriptions根据eventType保存在subscriptionsByEventType(Map集合)。注释3处按照订阅方法的优先级插入到订阅对象集合中,完成订阅方法的注册。注释4处通过subscriber获取subsrcibedEvents(事件类型集合)。如果subscribedEvents为null则重新创建,并将eventType添加到subscribedEvents中,并根据subscriber将subscribedEvents存储在typesBySubscriber(Map集合)。如果是粘性事件,则从stickyEvents事件保存队列中取出该事件类型的事件发送给当前订阅者。总结下,subscribe发法主要就是做了两件事:一件事是将Subscriptions根据eventType封装到subscriptionsByEventType中,将subscribedEvents根据subscriber封装到typesBySubscriber中;第二件事就是对粘性事件的处理。
喜欢的童鞋,动动手指点赞,收藏,转发,评论。增加博主更新动力!!!