EventBus|EventBus 源码分析(上篇)

可用于应用内的消息事件传递,方便快捷,耦合性低
1.基本用法
public class EventBusMain extends AppCompatActivity {@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.content_main); EventBus.getDefault().register(this); }- 订阅的事件 onEvent1 @Subscribe public void onEvent1(RemindBean bean){} - 订阅的事件 onEvent2 @Subscribe public void onEvent2(UserInfo bean){}@Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } }

需要发送消息传递的时候:
EventBus.getDefault().post(new RemindBean())

2.源码解读 放上官网的一张原理图,感觉挺清晰的:
EventBus|EventBus 源码分析(上篇)
文章图片
image.png 发布消息的一方(Publisher),只需要 post 一个 event 之后就不用管了,EventBus 内部会将event逐一分发给订阅此 event 的订阅者(Subscriber). 不错就是这样一个东西。
还记得以往我要实现两个不同的activity 之间要传递一些数据的时候,我都是通过定义一个interface的形式完成,时间一长,定义的接口一堆,在回顾查看代码也确实不够美观。好了话不多说,看下大家都在用的Eventbus.
3.首先
EventBus.getDefault().register(this);

getDefault():
EventBus 是一个单例模式,懒汉式,双重判断 /** 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; }

register 是什么意思呢,就是就跟你订阅报纸一样,报社需要确定几个重要的问题:
  • 订阅者是谁(Subscriber)?
  • 订阅的什么报纸(Event) ?
就是我认为比较重要的,那么register 这一步就是Subscriber 告诉 报社,订阅的event
public void register(Object subscriber) { - 1.先拿到这个订阅者(subscriber)类的字节码 Class subscriberClass = subscriber.getClass(); - 2. 通过这个类的字节码,拿到所有的订阅的 event,存放在List中 List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { - 3. 循环遍历所有的订阅的方法,完成subscriber 和 subscriberMethod 的关联 for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }

我们看下这个如何根据subscriberClass 找到这个订阅的 method的,findSubscriberMethods:
List findSubscriberMethods(Class subscriberClass) { - 1.先从缓存中取 List subscriberMethods = METHOD_CACHE.get(subscriberClass); - 2. 第一次肯定 null if (subscriberMethods != null) { return subscriberMethods; }- 3. 查找默认也是false,感兴趣的可以看下 if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass); } else {- 4. 所以是走这里 subscriberMethods = findUsingInfo(subscriberClass); } if (subscriberMethods.isEmpty()) { throw new EventBusException("Subscriber " + subscriberClass + " and its super classes have no public methods with the @Subscribe annotation"); } else { - 5. 找到之后添加到缓存中,key是 subscriber ; value 是:methods METHOD_CACHE.put(subscriberClass, subscriberMethods); return subscriberMethods; } }

看下:findUsingInfo(subscriberClass)
private List findUsingInfo(Class subscriberClass) { - 1. 我认为就是准备一个查找结果得存储对象 FindState findState = prepareFindState(); - 2. 将订阅者的subscriberClass 存储起来,保存在一个FindState 类中的subscriberClass 同时赋值给clazz变量中,以下代码能够看出 //void initForSubscriber(Class subscriberClass) { //this.subscriberClass = clazz = subscriberClass; //} findState.initForSubscriber(subscriberClass); while (findState.clazz != null) {进入循环中 //获取subscriberInfo 信息,返回null findState.subscriberInfo = getSubscriberInfo(findState); if (findState.subscriberInfo != null) { SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); } } } else { - 3. 进入到这里了 findUsingReflectionInSingleClass(findState); } - 4. 查找父类中的方法 findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }

findUsingReflectionInSingleClass 如下:
private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { // This is faster than getMethods, especially when subscribers are fat classes like Activities - 1. 通过订阅者的字节码查找当前类中所有生命的方法 methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 methods = findState.clazz.getMethods(); findState.skipSuperClasses = true; } - 2. 循环遍历所有的方法 for (Method method : methods) { - 3. 获取方法的修饰符 int modifiers = method.getModifiers(); - 4.判断修饰符,订阅方法的修饰符不能是private,static if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { - 5. 获取方法的所有的参数 Class[] parameterTypes = method.getParameterTypes(); - 6.判断参数的个数,只能有1个参数,订阅方法中 if (parameterTypes.length == 1) { - 7.获取方法上具有subscribe 注解 Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); - 8.含有subscribe注解的方法,就是该类订阅的方法,其它不符合的可能就是普通的方法 if (subscribeAnnotation != null) {- 9. 获取第一个参数eventType Class eventType = parameterTypes[0]; if (findState.checkAdd(method, eventType)) { - 10. 获取注解的mode,就是我们在注解上标识的, 有mainThread,Posting,background,async ThreadMode threadMode = subscribeAnnotation.threadMode(); - 11. 将订阅方法的一系列信息(方法名称,threadMode,优先级,是否是粘性等)添加到集合subscriberMethods中去 findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { - 12. 参数是多个的时候抛出异常 String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException("@Subscribe method " + methodName + "must have exactly 1 parameter but has " + parameterTypes.length); } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { - 13. 方法的修饰符不是public的,抛出异常String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } }

这样我们将所有信息都保存到findState 类中去了。再回头看我们原先那个方法,到第三步了:
private List findUsingInfo(Class subscriberClass) { - 1. 我认为就是准备一个查找结果得存储对象 FindState findState = prepareFindState(); - 2. 将订阅者的subscriberClass 存储起来,保存在一个FindState 类中的subscriberClass 同时赋值给clazz变量中,以下代码能够看出 //void initForSubscriber(Class subscriberClass) { //this.subscriberClass = clazz = subscriberClass; //} findState.initForSubscriber(subscriberClass); while (findState.clazz != null) {进入循环中 //获取subscriberInfo 信息,返回null findState.subscriberInfo = getSubscriberInfo(findState); if (findState.subscriberInfo != null) { SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); } } } else { - 3. 进入到这里了,上面已经分析所有信息保存到findState中 findUsingReflectionInSingleClass(findState); } - 4. 查找父类中的方法 findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }

在这个getMethodsAndRelease(findState):
private List getMethodsAndRelease(FindState findState) { - 1. 取出里面的subscriberMethods List subscriberMethods = new ArrayList<>(findState.subscriberMethods); findState.recycle(); synchronized (FIND_STATE_POOL) { for (int i = 0; i < POOL_SIZE; i++) { if (FIND_STATE_POOL[i] == null) { FIND_STATE_POOL[i] = findState; break; } } } - 2. 返回集合 return subscriberMethods; }

至此,我们知道了根据订阅者(subscriber)的clazz 找到了所有订阅的方法事件
methods
回到最初的第一步register:
public void register(Object subscriber) { Class subscriberClass = subscriber.getClass(); - 2. 完成 List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { - 3.循环遍历所有的订阅方法和订阅者之间建立关联 subscribe(subscriber, subscriberMethod); } } }

subscribe(subscriber, subscriberMethod) 方法:
// Must be called in synchronized block private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { - 1. 订阅方法的eventType的字节码 Class eventType = subscriberMethod.eventType; - 2. 订阅者和订阅方法封装成一个Subscription 对象 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); - 3. subscriptionsByEventType 第一次也是null ,根据eventType CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); - 4. 第一次肯定为null if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); - 5. key 为 eventType, value 是subscriptions对象 subscriptionsByEventType.put(eventType, subscriptions); } else { - 抛出异常 if (subscriptions.contains(newSubscription)) { throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } }- 6. 获取所有添加的subscriptions int size = subscriptions.size(); for (int i = 0; i <= size; i++) { - 7. 会判断每个订阅方法的优先级,添加到这个 subscriptions中,按照优先级 if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } }- 8.获取订阅的方法集合 List> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); - 9. 为空添加到 typesBySubscriber typesBySubscriber.put(subscriber, subscribedEvents); } - 10. 订阅事件添加到subscribedEvents集合中去 subscribedEvents.add(eventType); - 11. 判断是否是粘性事件的关联 if (subscriberMethod.sticky) { 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). Set, Object>> entries = stickyEvents.entrySet(); for (Map.Entry, 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); } } }

到此,如果你跟着我一步步看到这里,应该大概明白一些了,还有一部分没完,就是register 前半部分完成订阅,存储等工作;剩下post(event) 方法就是将event 分发给相应订阅过此事件的订阅者了。
【EventBus|EventBus 源码分析(上篇)】EventBus 源码分析(下篇)

    推荐阅读