EventBus 源码分析
来源:互联网 发布:希捷 数据恢复 编辑:程序博客网 时间:2024/05/21 23:37
前言
上篇文章笔者简单介绍了 EventBus 的用法。本篇文章笔者将简单分析 EventBus 的源码。从上篇文章我们可以得知,要使用 EventBus 首先要调用 EventBus 的 register 方法注册(一般在 onCreate 方法中)。然后,定义被 Subscribe 注解的方法(用来接收由 post 方法发送的消息)。最后,调用 unregister 方法解注册(一般在 onDestroy 方法中)。所以,笔者注重分析 EventBus 的 register , post 方法的实现,以及 EventBus 是如何调用接收消息的方法的。
register
EventBus.getDefault().register(this);
我们一般调用上述代码进行注册,调用上述代码的类我们暂且称为注册类。其中 getDefault 方法获取 EventBus 的实例。register 方法源码如下:
public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
先来看 3 , 4 行:这里调用 subscriberMethodFinder.findSubscriberMethods(subscriberClass)
得到一个 SubscriberMethod 的 List 。其中 SubscriberMethod 是对注册类中接收消息的方法的 Method 对象的封装。subscriberMethodFinder 是 SubscriberMethodFinder 类型的,我们接着追踪 SubscriberMethodFinder 的 findSubscriberMethods 方法。
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass); } else { subscriberMethods = findUsingInfo(subscriberClass); } if (subscriberMethods.isEmpty()) { throw new EventBusException("Subscriber " + subscriberClass + " and its super classes have no public methods with the @Subscribe annotation"); } else { METHOD_CACHE.put(subscriberClass, subscriberMethods); return subscriberMethods; } }
第 2 行:List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
其中 METHOD_CACHE 是 Map
private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { // This is faster than getMethods, especially when subscribers are fat classes like Activities 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; } for (Method method : methods) { int modifiers = method.getModifiers(); if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1) { Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); if (subscribeAnnotation != null) { Class<?> eventType = parameterTypes[0]; if (findState.checkAdd(method, eventType)) { ThreadMode threadMode = subscribeAnnotation.threadMode(); findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { 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)) { String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } }
由上述代码可以看出,findUsingReflectionInSingleClass 获取注册类中定义的方法并且遍历这些方法,然后把 public 、非 static 、非 abstract 、非 synthetic 、一个参数的、并且被注解 Subscribe 标注的方法封装成 SubscriberMethod 对象。并添加到 List subscriberMethods 中。然后把 subscriberMethods 返回给 findUsingInfo 方法,并最终返回给 EventBus 的 register 方法。接下来我们重新回到 register 方法。
register 方法中第 6 7 8 行 对返回的 List subscriberMethods 的遍历并调用 subscribe 方法。subscribe 方法的源码如下:
// Must be called in synchronized block private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class<?> eventType = subscriberMethod.eventType; Subscription newSubscription = new Subscription(subscriber, subscriberMethod); CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); } else { if (subscriptions.contains(newSubscription)) { throw new EventBusException( "Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } } int size = subscriptions.size(); for (int i = 0; i <= size; i++) { if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } } List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); 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<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); } } }
在 subscribe 方法中,把
subscriberMethod 和注册类对象封装成 Subscription 对象 newSubscription 。 并将 newSubscription 添加到 CopyOnWriteArrayList subscriptions 中并且通过 subscriberMethod.priority 确定 newSubscription 在 subscriptions 中的位置。subscriberMethod.priority 其实就是方法执行的优先级。需要注意的是,subscriptions 会被保存到 subscriptionsByEventType 中,subscriptionsByEventType 是一个 Map ,其 key 是注册类中被注解的方法的参数的类型,也就是接受消息的方法的参数的类型。 至此 register 方法大概介绍完毕。下面来看 post 方法。
post
EventBus 的 post 方法 是 EventBus 用来发布消息的方法。 post 方法被调用后会将 post 方法的参数传递给相应的注册类中的相应的方法中,并调用此方法。这个过程是怎样的呢?请看 post 的源码:
/** Posts the given event to the event bus. */ public void post(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event); if (!postingState.isPosting) { postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } try { while (!eventQueue.isEmpty()) { postSingleEvent(eventQueue.remove(0), postingState); } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } }
由上述源码可以看出,第 4 , 5 行把 post 方法的参数添加到一个 List 中。第 8 行得到 post 方法是否是在 mian 线程中调用的。第 14 15 16 行对保存 post 方法参数的 List 遍历删除并调用 postSingleEvent 方法。在 postSingleEvent 方法中会调用 postSingleEventForEventType 方法。postSingleEventForEventType 方法的源码如下:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { subscriptions = subscriptionsByEventType.get(eventClass); } if (subscriptions != null && !subscriptions.isEmpty()) { for (Subscription subscription : subscriptions) { postingState.event = event; postingState.subscription = subscription; boolean aborted = false; try { postToSubscription(subscription, event, postingState.isMainThread); aborted = postingState.canceled; } finally { postingState.event = null; postingState.subscription = null; postingState.canceled = false; } if (aborted) { break; } } return true; } return false; }
在 postSingleEventForEventType 方法中通过参数的类型获取 subscriptionsByEventType 中相应的 Subscription 的 CopyOnWriteArrayList subscriptions。如果 subscriptions 不为空则遍历它,并调用 postToSubscription 。postToSubscription 的源码如下:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { case POSTING: invokeSubscriber(subscription, event); break; case MAIN: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; case BACKGROUND: if (isMainThread) { backgroundPoster.enqueue(subscription, event); } else { invokeSubscriber(subscription, event); } break; case ASYNC: asyncPoster.enqueue(subscription, event); break; default: throw new IllegalStateException( "Unknown thread mode: " + subscription.subscriberMethod.threadMode); } }
由上述代码可以看出,postToSubscription 通过注解 Subscription 的属性 threadMode 的值,决定相应的接受信息的方法在哪个线程里调用。调用的规则已经在上篇文章中阐述过,这里不再赘述。invokeSubscriber 方法其实就是利用反射来实现接受信息的方法的调用的,这里也不再详细说明。
总结
EventBus 的实现其实就是一个典型的观察者模式。注册类向 EventBus 注册,当有消息需要发送的时候 EventBus 通过 post 方法向注册者们分发消息,其实就是遍历调用注册类中符合要求的方法。
- EventBus 2.4 源码分析
- EventBus源码注释分析
- EventBus框架源码分析
- EventBus源码分析
- EventBus源码分析
- EventBus 源码分析
- EventBus 源码分析
- EventBus的源码分析
- EventBus 3 源码分析
- EventBus 源码分析
- EventBus的源码分析
- EventBus源码分析
- EventBus源码分析
- EventBus源码分析
- EventBus源码分析
- EventBus 3.0 源码分析
- EventBus 3.0 源码分析
- EventBus源码分析
- Access Violation(非法访问)错误的解决方法
- The JSP specification requires that an attribute name is preceded by whitespace
- ADB server didn't ack * failed to start daemon及unable to obtain result of 'adb versio错误
- 窗体操作一切正常,为什么在form.free;时会出现Invalid pointer operation(无效的指针操作)的错误提示?
- 一次ora-600 ktubko_1故障简单分析
- EventBus 源码分析
- mysql 主从复制问题'the master returned an invalid number of fields for SHOW SLAVE HOSTS'
- theano - scan - 个人理解
- 控制字数输入
- java.lang.IllegalArgumentException: invalid value for field
- Linux内核中ioremap映射的透彻理解
- vmware 父虚拟磁盘的容量与子磁盘的容量不同。导致无法打开虚拟机
- JS如何进行
- imooc学习笔记--屏幕适配