参考:
Android每周一轮子:EventBus
Android开源框架源码鉴赏:EventBus
EventBus 3.0.0高效使用及源码解析
Android 框架学习2:源码分析 EventBus 3.0 如何实现事件总线
老司机教你 “飙” EventBus 3
使用示例
1 | public class MainActivity extends AppCompatActivity { |
在接受消息的这个Activity中, 我们注册了当前activity, 在activity destroy的时候取消注册, 然后新建一个方法, 添加@Subscribe的注解, 注意只能是public的, 方法名可以随便取, 在这个方法里接收发出的事件.
然后我们在另一个Activity里发出事件
1 | public class SecondActivity extends AppCompatActivity { |
这样在MainActivity里就能接收到发出的消息了
EventBus.getDefault()
首先看EventBus.getDefault()
1 | public static EventBus getDefault() { |
这是一个典型的DCL的单例
register(Object subscriber)
我们看一下register()
方法
1 | public void register(Object subscriber) { |
首先获取订阅实例的类, 然后寻找该类中的所有订阅方法, 然后对这些方法调用订阅方法.
看一下这个findSubscriberMethods(Class<?> subscriberClass)
方法
1 | List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { |
首先从缓存中寻找方法, 如果没有, 那就使用反射或者usinginfo来寻找方法, 如果还没有那就要报错了, 说明这个订阅者对象的类以及它的父类中没有public的带有@Subscribe注解的方法.如果找到了, 那就放入缓存.
在这里我打断点发现会使用后面那一种findUsingInfo的方法, 我们看一下
1 | private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { |
再次打了一下断点, 发现还是会走反射的方法(代码中注释的地方), 看一下吧
1 | private void findUsingReflectionInSingleClass(FindState findState) { |
在这里首先获取了订阅者类中的public方法, getDeclaredMethods()
和getMethods()
方法的区别在于: getDeclaredMethods()
获取包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法, getMethods()
获取所有公用(public)方法包括其继承类的公用方法.
然后遍历这些方法.只有符合这些条件的方法才是符合要求的:
- 权限修饰符是public或者procected的(可能还有别的, 但是private是不行的), 非static
- 只有一个参数
- 含有Subscribe注解
如果有这样的方法, 那就根据这个方法, 消息类, threadMode, priority, sticky生成一个SubscriberMethod()对象, 然后添加到findState的subscriberMethods集合中去
现在我们回到findUsingInfo(Class<?> subscriberClass)
方法, 这里这个findState
现在已经保存了那些订阅方法了, 然后把这些方法(包括其中的参数)放在一个集合中然后return出去
现在我回到register(Object subscriber)
方法, 在获取了订阅者的所有订阅方法之后, 我们遍历这些方法, 对每一个方法调用subscribe(Object subscriber, SubscriberMethod subscriberMethod)
方法
1 | private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { |
在这个方法中, 主要做了这些事:
- 传入订阅者和事件类型生成一个新的订阅对象
- 根据事件类型从map中获取了一个订阅对象的集合, 如果这个集合还不存在, 就new一个, 然后以事件类型为key, 这个集合为value添加到一个map里
- 如果这个集合存在, 对这个订阅对象进行检查, 如果订阅对象的集合中已经包含有重复的订阅对象, 就报错, 可以看注释中写的.所以说
EventBus.getDefault().register(this)
这个方法在同一个类里面是不可以被调用两次的 - 遍历这个集合, 按照事件的优先级将新的订阅对象添加到集合中去
- 根据订阅者从map中获取了一个消息类型的集合, 如果这个集合还不存在, 就new一个, 将事件类型添加到这个集合中
- 黏性事件的处理, 暂时不研究
post(Object event)
1 | public void post(Object event) { |
currentPostingThreadState
是一个ThreadLocal, 初始值是new了一个PostingThreadState
看一下postSingleEvent(eventQueue.remove(0), postingState);
这句代码吧
1 | private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { |
看一下postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass)
的代码
1 | private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { |
subscriptionsByEventType
是一个map, 我们register的时候也用到过.它的key是事件的class, value是一个Subscription
的list. 在这里会根据事件的class, 将所有订阅了这个消息类型的订阅对象(注意不是订阅者而是用订阅者和订阅方法生成的订阅对象)的列表取出来.
我们再看一下postToSubscription(Subscription subscription, Object event, boolean isMainThread)
这个方法
1 | private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { |
因为subscriberMethod的线程模式默认是POSTING, 所以我们看一下POSTING
1 | void invokeSubscriber(Subscription subscription, Object event) { |
可以看着这里使用了反射, 传入了方法的调用对象订阅者, 和方法参数事件对象, 然后Method.invoke(Object obj, Object... args)
todo(以后有时间了再补充)
黏性事件
所谓的黏性事件大意就是先发出事件, 然后等有对象注册了再立刻调用.大胆猜想就是在注册的时候检查这个订阅方法事件是否是黏性的, 如果是就找到对应这个事件类型的事件, 然后调用.
待续…
四种不同的线程模型
待续…
取消注册
待续…
编译时注解eventBusIndex
待续…
简单总结
简单总结一下Eventbus的原理
EventBus.getDefault().register(this);
这一句会扫描这个订阅者中的订阅方法, 将每个方法和订阅者包装成Subscription, 添加到list中, 然后又把list放到以事件类型class对象的map中, 方便以后查找EventBus.post(Object object)
这句会在上面的map中查找所对应的订阅者和订阅方法, 然后使用反射, 让订阅者调用订阅方法, 传入的参数就是这个发送的消息事件
用两张图说明下
register
post