EventBus的源码分析:SubscriberMethodFinder和订阅流程

最近在看EventBus的源码,想看看它好在哪里,跟广播相比,如果只是在app内通知获取数据,那用eventBus要相对方便得多,但如果是跨进程,那还是用广播吧,而且EventBus一次post只能传一个类,除非这个onEvent没有其它重载的函数,不然会抛异常:
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
        + eventType) ;
看了整个流程,第一个重要的类是:SubscriberMethodFinder,涉及到EventBus的订阅跟发布。
如果是系统类了就跳过获取,再把这个类以及它的父类相关的onEvent方法找到,加入到subscriberMethods里去。
List<SubscriberMethod> findSubscriberMethods (Class<?> subscriberClass) {
    List<SubscriberMethod> subscriberMethods
;
    synchronized
( methodCache ) {
        subscriberMethods =
methodCache .get(subscriberClass) ;
   
}
   
if (subscriberMethods != null ) {
       
return subscriberMethods ;
   
}
    subscriberMethods =
new ArrayList<SubscriberMethod>() ;
   
Class<?> clazz = subscriberClass ;
   
HashMap<String , Class> eventTypesFound = new HashMap<String , Class>() ;
   
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;
       
}

       
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
       
try {
           
// This is faster than getMethods, especially when subscribers a fat classes like Activities
           
Method[] methods = clazz.getDeclaredMethods() ;
           
filterSubscriberMethods(subscriberMethods , eventTypesFound , methodKeyBuilder , methods) ;
       
} catch (Throwable th) {
           
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
           
Method[] methods = subscriberClass.getMethods() ;
           
subscriberMethods.clear() ;
           
eventTypesFound.clear() ;
           
filterSubscriberMethods(subscriberMethods , eventTypesFound , methodKeyBuilder , methods) ;
            break;
       
}
        clazz = clazz.getSuperclass()
;
   
}
   
if (subscriberMethods.isEmpty()) {
       
throw new EventBusException( "Subscriber " + subscriberClass + " has no public methods called "
               
+ ON_EVENT_METHOD_NAME ) ;
   
} else {
       
synchronized ( methodCache ) {
           
methodCache .put(subscriberClass , subscriberMethods) ;
       
}
       
return subscriberMethods ;
   
}
}
如果是以onEvent开头的,就继续看这个函数的名称,看是放在哪个线程,先分析filerSubscriberMethobs函数。
事件类型是由方法名+第一个参数类型组成,new 一个由方法名,线程,事件类型组成的订阅者放到这个与这个类相应的list里。
private void filterSubscriberMethods (List<SubscriberMethod> subscriberMethods ,
                                    
HashMap<String , Class> eventTypesFound , StringBuilder methodKeyBuilder ,
                                    
Method[] methods) {
   
for (Method method : methods) {
        String methodName = method.getName()
;
        if
(methodName.startsWith( ON_EVENT_METHOD_NAME )) {
           
int modifiers = method.getModifiers() ;
           
Class<?> methodClass = method.getDeclaringClass() ;
            if
((modifiers & Modifier. PUBLIC ) != 0 && (modifiers & MODIFIERS_IGNORE ) == 0 ) {
                Class<?>[] parameterTypes = method.getParameterTypes()
;
                if
(parameterTypes. length == 1 ) {
                    ThreadMode threadMode = getThreadMode(methodClass
, method , methodName) ;
                    if
(threadMode == null ) {
                       
continue;
                   
}
                   
// 第一个参数类型
                   
Class<?> eventType = parameterTypes[ 0 ] ;
                   
methodKeyBuilder.setLength( 0 ) ;
                   
methodKeyBuilder.append(methodName) ;
                   
methodKeyBuilder.append( '>' ).append(eventType.getName()) ;
                   
String methodKey = methodKeyBuilder.toString() ;
                   
Class methodClassOld = eventTypesFound.put(methodKey , methodClass) ;
                   
// 如果子类重写了父类的 onEvent 方法,只放入子类的
                   
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
                       
// Only add if not already found in a sub class
                       
subscriberMethods.add( new SubscriberMethod(method , threadMode , eventType)) ;
                   
} else {
                       
// Revert the put, old class is further down the class hierarchy
                       
eventTypesFound.put(methodKey , methodClassOld) ;
                   
}
                }
            }
else if (! skipMethodVerificationForClasses .containsKey(methodClass)) {
                Log.
d(EventBus.
TAG , "Skipping method (not public, static or abstract): " + methodClass + "."
                       
+ methodName) ;
           
}
        }
    }
}
看看onEvent后是什么字段,比如:MainThread。
private ThreadMode getThreadMode (Class<?> clazz , Method method , String methodName) {
    String modifierString = methodName.substring(
ON_EVENT_METHOD_NAME .length()) ;
   
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)) {
           
throw new EventBusException( "Illegal onEvent method, check for typos: " + method) ;
       
} else {
            threadMode =
null;
       
}
    }
   
return threadMode ;
}

从这个类可知,这个类是用来在调用EventBus.getDefault().register(this)的时候,获取当前这个类的订阅方法的,以方法+第一个参数类型来做为eventType来做为订阅类型,统一放到SubscribeMethod里。
接下来就可以讲订阅流程了。
首先是
/** 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 ;
}
通过单例来使用EventBus,EventBus有几个register函数,但都会统一调用下面这个函数。
private synchronized void register (Object subscriber , boolean sticky , int priority) {
   
// 获得与这个类相对应的订阅方法,放到 SubScriberMethod
   
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder .findSubscriberMethods(subscriber.getClass()) ;
    for
(SubscriberMethod subscriberMethod : subscriberMethods) {
       
subscribe(subscriber
, subscriberMethod , sticky , priority) ;
   
}
}
从这个函数可知,会先获取到这个类的onEvnent的订阅方法,在对每个方法进行订阅。在对这个类的每个函数进行注册时,做了三件事,
第一件是在subscriptionsByEventType里放入这个eventType的订阅者:Subsctiption(由类类型,方法,优先级),并且按优先级排序。第二件事在typesByScubscriptions是放入类型对应该的所有订阅,最后还要用于解除注册。第三步是 判断sticky;如果为true,从stickyEvents中根据eventType去查找有没有stickyEvent,如果有则立即发布去执行。stickyEvent其实就是我们post时的参数
// 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) ;
   
// 放入一个同个类作为 eventType 也就是参数 0 的订阅列表
   
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) {
       
// 是否支持继承,默认是支持
       
// 判断 sticky ;如果为 true ,从 stickyEvents 中根据 eventType 去查找有没有 stickyEvent ,如果有则立即发布去执行。 stickyEvent 其实就是我们 post 时的参数
       
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) ;
       
}
    }
}

接下来是解除注册:
找到这个类的所有订阅类型并移除这个订阅类。
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister (Object subscriber) {
   
// 找到这个类的所有订阅类型
   
List<Class<?>> subscribedTypes = typesBySubscriber .get(subscriber) ;
    if
(subscribedTypes != null ) {
       
for (Class<?> eventType : subscribedTypes) {
            unsubscribeByEventType(subscriber
, eventType) ;
       
}
       
typesBySubscriber .remove(subscriber) ;
   
} else {
        Log.
w(
TAG , "Subscriber to unregister was not registered before: " + subscriber.getClass()) ;
   
}
}
找到与这个订阅类型相关的订阅类,移除
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType (Object subscriber , Class<?> eventType) {
   
// 找到与这个订阅类型的订阅类,移除
   
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-- ;
           
}
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值