前文
由于EventBus的源码还是比较的复杂的,打算使用五篇文章从浅入深的分析它的源码。包括:
- post流程的分析
- register流程分析(反射方式)【本文】
- register流程分析(注解方式)
- stickey消息实现和处理
- 最佳实践
register的流程
我们再使用过程中,都需要在页面调用register(obj)进行注册,这样我们的使用了@Subscribe注解的方法才能接受消息。本文就是主要去讲解这个注册的流程。
在EventBus3.x之后,它新增了一种注解的方式,让我们通过编译期就能知道那些方法是需要接受消息的(即@Subscribe注解的方法),在之前,他是只有通过运行时通过反射+缓存的方式,这种方式会一定程度的降低代码执行速度,所以就新增了一种,我们这里就先分析通过反射的方式去查找被@Subscribe注解的方法。需要注意的时候,查找这些方法可以通过注解进行运行时效率的优化,但是post消息的时候还是通过反射去调用的,这个的效率是没有降低的。
属性定义
首先,我们先看一下对一个事件的定义的属性有那些,类名称是SubscriberMethod,需要与SubscriberMethodInfo区分开,后者是用于注解生成的,他会转化成SubscriberMethod,这些我们再注解篇中再说。
1 | public class SubscriberMethod { |
Subscription类
1 |
|
register流程
通过EventBus的register方法发起,具体的查找被@Subscribe注解的方法是在findSubscriberMethods中
1 | public void register(Object subscriber) { |
我们开始看下findSubscriberMethods是如何查询得到我们页面使用了@Subscribe方法的,看下整个的查找流程。
1 | List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { |
本文是讲解的反射的方式,我们就只关注关注findUsingReflection方法
1 | private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) { |
我们看下其中prepareFindState和getMethodsAndRelease方法,看下它为何是使用了长度为4的作为缓存?
1 | //从FIND_STATE_POOL读取缓存的FindState对象,如果不存在,则新生成一个,他会在getMethodsAndRelease中存入FIND_STATE_POOL缓存 |
然后我们看下findUsingReflection他的核心循环方法
1 | private void findUsingReflectionInSingleClass(FindState findState) { |
我们看下checkAdd方法是
1 | boolean checkAdd(Method method, Class<?> eventType) { |
当完成了一次findUsingReflectionInSingleClass()方法调用之后,会调用findState.moveToSuperclass()进行下一个clazz的查找,如果没有,则findUsingReflection结束,
1 | void moveToSuperclass() { |
所以findUsingReflection(Class<?> subscriberClass)的流程图大致如下

当流程整体清晰了之后,我们再探讨下checkAdd()的作用,它在findUsingReflectionInSingleClass中被调用,他返回了true才可以得到有效的【订阅方法】,返回了false就会丢掉。我们来列举下面的一些情况,这些情况的前提method都必须使用了@Subscribe注解并且是符合规则是(比如非抽象,参数只有一个等)。
1 | class Foo { |
Test是我们的页面,我们会在Test中去调用EventBus的register方法,然后看checkAdd()的走势
- 首次的时候,查找的是
Test的test,我们的anyMethodByEventType肯定是没有对应的method,这时候是返回了true。 - 然后是查找到
Test的test2方法,然后发现existing是有值的,类型是method,然后第一次执行checkAddWithMethodSignature,methodKeyBuilder值为test>Java.lang.String,methodClass是Test,methodClassOld为null,返回true,所以不会抛出IllegalStateException,然后把anyMethodByEventTypeeventType对应的值修改为当前FindState,第二次执行checkAddWithMethodSignature,methodKeyBuilder值为tes2t>Java.lang.String,methodClassOld为null,返回了true。 - 然后循环到
Foo2类,existing值是FindState,并更新anyMethodByEventType的eventType对应值未对应的method,执行checkAddWithMethodSignature,methodKeyBuilder值为test>Java.lang.String,methodClass是Foo,methodClassOld是Test,返回了false,然后checkAdd返回了false,并且把subscriberClassByMethodKey的值设置为了Test,所以Foo2中的Test方法并不是有效的【订阅方法】 - 再次循环到
Foo,这时候existing是Foo2类的test方法,然后第一次走checkAddWithMethodSignature,methodKeyBuilder值为test>Java.lang.String,methodClass是Foo2,methodClassOld是Test,返回false,抛出异常。
通过上面的流程分析,我们知道上面的代码会抛出异常,而且就算只有两层继承(没有Foo类),父类的方法也不会被统计为有效的【订阅方法】
通过这个流程,我们再回头看下FindState类的组成,它的每个成员的作用进行描述:
1 | static class FindState { |
通过分析上面的流程,我们可以知道一些关于重载与继承订阅方法的特点
- 子类
Override了父类的方法,两个方法都是使用了@Subscribe注解的时候,父类的会失效,不会被统计到为有效方法中,但是分发的时候也可以分发给该方法(配置篇和post()流程篇有说)。 - 一个方法
Override>=2次,并且,假如还具有一个额外的Overload方法,那么调用register就会抛出异常。 - 假如父类有
@Subscribe注解方法, 子类没有去重写,则post消息的时候他也是能收到的,也是有效的订阅方法