EventBus 3.0源码解析
2017-03-26 15:31
417 查看
一、Register过程
1、首先看我们常用的getDefault方法:
2、接下来看EventBus的两个构造函数:
3、在组件中注册的函数register
4、findSubscriberMethods函数负责寻找到该类中的相应函数,即被@Subscribe注解修饰的函数
4000
eratedIndex(表示是否忽略注解生成器的索引,默认为false),选择使用findUsingReflection或者findUsingInfo来获取Subscriber方法,使用索引当然会有更快的速度。
6、若不使用注解生成的索引则会转入findUsingReflectionInSingleClass函数
7、返回第3步,我们找到了所有的Subscriber方法后,遍历里面每一个方法,将相应类和方法传入Subscribe方法
将方法按照不同的事件类型将方法信息传入subscriptionByEventType中,待post中使用。另外将方法信息传入到subscribeEvnets待unregister函数使用。若设置了Sticky,则进行相关操作。至此EvnetBus的注册过程就结束了。
二、事件分发过程
1、最常用的post方法进行事件的分发
2、postSingleEvnet对每一个即将要分发的事件做处理
3、postSingleEventForEventType方法从subscriptionByEventType对象中获取所有的订阅者信息,进一步调用postToSubscription方法
4、postToSubscription方法根据订阅方法的不同线程模式,以及post方法所在的线程进行不同的事件分发操作
主要说明前三种线程模式的情况:
若订阅者的线程模式为Posting(和post方法在同一线程,默认为此种模式),则直接调用invokeSubscriber;
若订阅者的线程模式为Main(在主线程中进行),则需进一步判断post方法所在线程,若post方法也在main线程,则直接invoke,若不在,则将这个事件交给mainThreadPoster处理,该对象是一个主线程的handler对象。
若订阅者的线程模式为BACKGROUND(在后台线程中进行),则需进一步判断post方法所在线程,若post方法在main线程中,将这个事件交给backgroundPoster处理,该对象是一个后台线程线程的runable对象,若不在则直接invoke。
4、invokeSubscriber方法完成最终方法的调用
使用反射机制,获取到消息相应函数,调用该函数,并将参数传入改函数,最终完成事件的分发。
是不是觉得很简单?接下来我们可以自己实现一个总线事件框架。
1、首先看我们常用的getDefault方法:
/** 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; }这是一个非常典型的线程安全的懒汉式单例模式。
2、接下来看EventBus的两个构造函数:
public EventBus() { this(DEFAULT_BUILDER); } EventBus(EventBusBuilder builder) { subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; sendNoSubscriberEvent = builder.sendNoSubscriberEvent; throwSubscriberException = builder.throwSubscriberException; eventInheritance = builder.eventInheritance; executorService = builder.executorService; }EvnetBus使用Builder进行初始化,如果用户不指定builder,则使用系统默认的builder。
3、在组件中注册的函数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); } } }其中subscriber对象我们一般传的是this,根据这个对象获取相应的类,并根据这个类寻找该类中的所有subscriber方法(即响应函数)。
4、findSubscriberMethods函数负责寻找到该类中的相应函数,即被@Subscribe注解修饰的函数
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; } }METHODE_CACHE缓存是一个Map<Class<?>,List<SubscriberMethod>>对象,首先从换该缓存中寻找是否有过缓存,有则直接返回,没有的话根据builder中的一个参数ignoreGen
4000
eratedIndex(表示是否忽略注解生成器的索引,默认为false),选择使用findUsingReflection或者findUsingInfo来获取Subscriber方法,使用索引当然会有更快的速度。
6、若不使用注解生成的索引则会转入findUsingReflectionInSingleClass函数
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"); } } }该函数则遍历该类的所有方法,发现有被@Subscribe注解修饰的方法则把该方法联通事件类型,线程模式,优先级,是否是stiky事件一并放入findState里的List<SubscriberMethod>对象中,再将此对象返回给第4步中的subscriberMethods,从而找到了注册类中的Subscriber事件相应函数。
7、返回第3步,我们找到了所有的Subscriber方法后,遍历里面每一个方法,将相应类和方法传入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); } } }
将方法按照不同的事件类型将方法信息传入subscriptionByEventType中,待post中使用。另外将方法信息传入到subscribeEvnets待unregister函数使用。若设置了Sticky,则进行相关操作。至此EvnetBus的注册过程就结束了。
二、事件分发过程
1、最常用的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; } } }首先获取到post当前的线程情况,当前线程的情况保存在一个ThreadLocal对象中。把即将要分发的事件加入事件队列中,使用postSingleEvent方法分发队列中每一个事件。
2、postSingleEvnet对每一个即将要分发的事件做处理
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; if (eventInheritance) { List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); int countTypes = eventTypes.size(); for (int h = 0; h < countTypes; h++) { Class<?> clazz = eventTypes.get(h); subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); } } else { subscriptionFound = postSingleEventForEventType(event, postingState, eventClass); } if (!subscriptionFound) { if (logNoSubscriberMessages) { Log.d(TAG, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } } }不管evnetInheritance(表示是否寻找其父类中的事件相应函数,默认为true)参数为true或false,方法最终都进入postSingleEvnetForEventType方法。
3、postSingleEventForEventType方法从subscriptionByEventType对象中获取所有的订阅者信息,进一步调用postToSubscription方法
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; }
4、postToSubscription方法根据订阅方法的不同线程模式,以及post方法所在的线程进行不同的事件分发操作
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); } }
主要说明前三种线程模式的情况:
若订阅者的线程模式为Posting(和post方法在同一线程,默认为此种模式),则直接调用invokeSubscriber;
若订阅者的线程模式为Main(在主线程中进行),则需进一步判断post方法所在线程,若post方法也在main线程,则直接invoke,若不在,则将这个事件交给mainThreadPoster处理,该对象是一个主线程的handler对象。
若订阅者的线程模式为BACKGROUND(在后台线程中进行),则需进一步判断post方法所在线程,若post方法在main线程中,将这个事件交给backgroundPoster处理,该对象是一个后台线程线程的runable对象,若不在则直接invoke。
4、invokeSubscriber方法完成最终方法的调用
void invokeSubscriber(Subscription subscription, Object event) { try { subscription.subscriberMethod.method.invoke(subscription.subscriber, event); } catch (InvocationTargetException e) { handleSubscriberException(subscription, event, e.getCause()); } catch (IllegalAccessException e) { throw new IllegalStateException("Unexpected exception", e); } }
使用反射机制,获取到消息相应函数,调用该函数,并将参数传入改函数,最终完成事件的分发。
是不是觉得很简单?接下来我们可以自己实现一个总线事件框架。
相关文章推荐
- EventBus 3.0进阶:源码及其设计模式 完全解析
- EventBus 3.0 源码解析
- EventBus 3.0源码解析
- EventBus3.0源码解析
- EventBus 3.0源码解析
- Android EventBus 3.0 使用及源码解析一
- Android EventBus源码解析
- Android之EventBus概述及源码解析(雷惊风)
- EventBus---EventBus源码解析 带你深入理解EventBus
- [EventBus源码解析] EventBus.post 方法详述
- android EventBus源码解析
- Android EventBus源码解析 带你深入理解EventBus
- Redis 3.0 源码解析---底层数据结构分析(3)
- [EventBus源码解析] EventBus.register 方法详述
- EventBus框架原理解析(结合源码)(上)
- Android EventBus源码解析 带你深入理解EventBus
- 开源项目源码解析-EventBus 源码解析
- EventBus 利弊与源码解析
- Redis 3.0 源码解析---底层数据结构分析(2)
- EventBus 源码解析