内容简介:看了别人的源码文章,一开始有点懵,还要复习下反射和注解器的知识。然后自己也做了下笔记,加深印象。参考文章:
看了别人的源码文章,一开始有点懵,还要复习下反射和注解器的知识。然后自己也做了下笔记,加深印象。
参考文章:
www.jianshu.com/p/c4d106419… .
描述
EventBus是Android和 Java 的发布/订阅事件总线。
优缺点:
- 简化了组件之间的通信,将事件发布者和订阅者分离
- 代码简单
- 包体积小缺点:利用反射,性能可能会差一点。可以使用EventBus annotation processor(EventBus注解处理器),在编译期间创建了订阅者索引。(提升EventBus性能: greenrobot.org/eventbus/do…
三要素:
- Event:自定义事件类型
- Subscriber:事件订阅者。在EventBus3.0之前我们必须定义以onEvent开头的那几个方法,分别是onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,而在3.0之后事件处理的方法名可以随意取,不过需要加上注解@subscribe(),并且指定线程模型,默认是POSTING。
- Publisher:事件发布者。可以在任意线程里发布事件,一般情况下,使用EventBus.getDefault()就可以得到一个EventBus对象,然后再调用post(Object)方法即可。
4个线程:
- POSTING:在发布线程的事件执行
- MAIN:在主线程执行。
- BACKGROUND:如果发布事件的线程为主线程则新建一个线程执行,否则在发布事件的线程执行。
- ASYNC:在新的线程执行
利用Handler切换到主线程。BACKGROUND线程,使用到了线程池ExecutorService。
说说EventBus里面用到的知识点
- 注解处理器:
使用EventBus annotation processor(EventBus注解处理器),在编译期间创建了订阅者索引。(提升EventBus性能: greenrobot.org/eventbus/do… )。可以看到,会在build包下面生成一个EventBus的索引类。SUBSCRIBER_INDEX是一个Map类型数据,存放着每一个类里面的注解信息
/** This class is generated by EventBus, do not edit. */ public class MyEventBusIndex implements SubscriberInfoIndex { private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX; static { SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>(); putIndex(new SimpleSubscriberInfo(com.example.camera_learning.eventbus.EventBusActivity.class, true, new SubscriberMethodInfo[] { new SubscriberMethodInfo("onEvent", com.example.camera_learning.eventbus.TestEvent.class), new SubscriberMethodInfo("onEvent", com.example.camera_learning.eventbus.TestEvent2.class), })); } private static void putIndex(SubscriberInfo info) { SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info); } @Override public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) { SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass); if (info != null) { return info; } else { return null; } } } 复制代码
- 反射
如果索引类中有缓存相关的注解信息的话,那就会直接用索引类里面的注解信息。如果没有的话,就需要利用反射去获取类中的所有方法,然后拿到有@Subscribe的方法。
post方法最后需要利用invoke来调用订阅者对象的订阅方法(具体代码可以看下面)
- 设计模式:单例模式、建造者模式、观察者模式
- ThreadLocal:EventBus会通过ThreadLocal为每个线程维护一个PostingThreadState对象。
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } }; final static class PostingThreadState { //分发队列 final List<Object> eventQueue = new ArrayList<>(); //是否正在分发 boolean isPosting; //是否是主线程 boolean isMainThread; //订阅关系 Subscription subscription; //当前正在分发的事件 Object event; //是否取消 boolean canceled; } 复制代码
EventBus里面的一些数据结构
比较重要的就是下面两个map集合。
//key为事件类型,value值为Subscription的集合。这样可以根据事件的类型,直接获取订阅该事件的所有类中的所有方法 private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; //key为订阅对象,value为该类中的所有订阅事件类型的集合。 private final Map<Object, List<Class<?>>> typesBySubscriber; //粘性事件 private final Map<Class<?>, Object> stickyEvents; //Subscription类,表示一个订阅关系,包含订阅对象和订阅方法 final class Subscription { final Object subscriber; final SubscriberMethod subscriberMethod; } 复制代码
阅读源码
getDefault()方法
- 利用双重校验锁实现单例模式,保证线程安全
- 使用Builder建造者模式,将一个复杂对象的构建和它的表示分离。建造者模式一般用来创建复杂对象,用户可以不用关心其建造过程和细节。在EventBus中,指的是EventBusBuilder类,可以使用自定义参数创建EventBus实例。
public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; } public EventBus() { this(DEFAULT_BUILDER); } EventBus(EventBusBuilder builder) { logger = builder.getLogger(); subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); mainThreadSupport = builder.getMainThreadSupport(); mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; 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; } public class EventBusBuilder { private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool(); boolean logSubscriberExceptions = true; boolean logNoSubscriberMessages = true; boolean sendSubscriberExceptionEvent = true; boolean sendNoSubscriberEvent = true; boolean throwSubscriberException; boolean eventInheritance = true; boolean ignoreGeneratedIndex; boolean strictMethodVerification; ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; List<Class<?>> skipMethodVerificationForClasses; List<SubscriberInfoIndex> subscriberInfoIndexes; Logger logger; MainThreadSupport mainThreadSupport; EventBusBuilder() { } /** Builds an EventBus based on the current configuration. */ public EventBus build() { return new EventBus(this); } 复制代码
register方法
register的最终目的是,将注解的信息保存到对应的map中。而获取的过程,优先通过注解器生成的注解信息获取,如果没有的话,再利用反射获取注解方法。
public void register(Object subscriber) { //拿到class对象 Class<?> subscriberClass = subscriber.getClass(); //利用SubscriberMethodFinder类来找出这个类中的所有订阅方法 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); //拿到类中所有的订阅方法后,调用subscribe方法 synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } } 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); } } } 复制代码
下面看一下SubscriberMethodFinder类。
//这个map对象,key值为订阅者类,value为该类中的所有订阅方法的list集合。已经register过的话,相应的数据已经在map中存在了,这个时候就可以直接从map中读取就行了,不用再次利用反射进行多余的遍历类中的方法。有点空间换时间的思想。 private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>(); //通过这个方法,遍历出某个类中的所有订阅方法 List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { //根据缓存值,判断是否注册过EventBus List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } //默认为false,所以一般是先走findUsingInfo方法,通过自动生成的索引类比如MyEventBusIndex来获取到被注解的办法。这种办法比通过findUsingReflection()利用反射去获取方法的性能好一点。如果没有获取到索引中存储的订阅者Subscriber信息的话,才去走利用反射的办法。 if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass); } else { subscriberMethods = findUsingInfo(subscriberClass); } //如果订阅者类和父类中,没有@Subscribe利用监听事件的方法,就会抛这个错误。 if (subscriberMethods.isEmpty()) { throw new EventBusException("Subscriber " + subscriberClass + " and its super classes have no public methods with the @Subscribe annotation"); } else { //获取到订阅者类中的所有注解方法后,保存到cache中 METHOD_CACHE.put(subscriberClass, subscriberMethods); return subscriberMethods; } } //利用注解处理器生成的索引类,来获取类中的订阅方法 private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { //在生成的索引类中,获取保存的订阅信息 findState.subscriberInfo = getSubscriberInfo(findState); if (findState.subscriberInfo != null) { //获取拿到这个订阅类中的所有的订阅方法 SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); //遍历,检查后,添加到list集合 for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); } } } else { //如果在索引类中找不到订阅信息,那就通过反射的办法来获取 findUsingReflectionInSingleClass(findState); } findState.moveToSuperclass(); } return getMethodsAndRelease(findState); } //在生成的索引类中,获取保存的订阅信息 private SubscriberInfo getSubscriberInfo(FindState findState) { if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) { SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo(); if (findState.clazz == superclassInfo.getSubscriberClass()) { return superclassInfo; } } //如果subscriberInfoIndexes为空,也就是没有利用生成索引的办法来提高EventBus性能,直接返回null //不为空的话,遍历,拿到这个订阅类中的所有注解方法 if (subscriberInfoIndexes != null) { for (SubscriberInfoIndex index : subscriberInfoIndexes) { SubscriberInfo info = index.getSubscriberInfo(findState.clazz); if (info != null) { return info; } } } return null; } //使用subscribe方法 private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { //订阅方法的事件类型 Class<?> eventType = subscriberMethod.eventType; //创建一个Subscription,包含订阅类对象和订阅方法 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); //获取到这种事件类型的list集合 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { //保存到subscriptionsByEventType里面,key为事件类型,value为Subscription 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); } } } 复制代码
post方法
post方法最后会走到postSingleEventForEventType方法,拿到注册这个事件的订阅者信息,利用反射调用订阅方法的执行。
public void post(Object event) { //获取当前线程的PostingThreadState对象 PostingThreadState postingState = currentPostingThreadState.get(); //获取当前的分发队列 List<Object> eventQueue = postingState.eventQueue; //将事件添加到队列中 eventQueue.add(event); if (!postingState.isPosting) { postingState.isMainThread = isMainThread(); 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; } } } 复制代码
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { //去map集合中,根据事件类型,获取到所有的订阅方法 subscriptions = subscriptionsByEventType.get(eventClass); } if (subscriptions != null && !subscriptions.isEmpty()) { //遍历订阅该事件的list集合 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; } //根据线程进行分发事件 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 MAIN_ORDERED: if (mainThreadPoster != null) { mainThreadPoster.enqueue(subscription, event); } else { // temporary: technically not correct as poster not decoupled from subscriber invokeSubscriber(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); } } //最后是利用反射,调用订阅者对象的订阅方法 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); } } 复制代码
unregister方法
unregister方法就是要把这个类中的注解信息都给移除掉。
public synchronized void unregister(Object subscriber) { //获取这个订阅者种的所有订阅事件类型list List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { for (Class<?> eventType : subscribedTypes) { //遍历事件类型list,移除subscriptionsByEventType中包含这个订阅者的所有订阅关系 unsubscribeByEventType(subscriber, eventType); } //移除这个订阅对象 typesBySubscriber.remove(subscriber); } else { logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } } //移除subscriptionsByEventType中包含这个订阅者的所有订阅关系 private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { int size = subscriptions.size(); for (int i = 0; i < size; i++) { Subscription subscription = subscriptions.get(i); if (subscription.subscriber == subscriber) { subscription.active = false; subscriptions.remove(i); i--; size--; } } } } 复制代码
以上所述就是小编给大家介绍的《EventBus源码学习》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
SHA 加密
SHA 加密工具
html转js在线工具
html转js在线工具