前文
由于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
,然后把anyMethodByEventType
eventType对应的值修改为当前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
消息的时候他也是能收到的,也是有效的订阅方法