EventBus3.0源码学习(1) register和unregister
引子
EventBus提供了一套完善的总线机制,能有效地用于模块间解耦。要使用EventBus,在项目模块的build.gradle中添加如下依赖即可:
dependencies { compile 'org.greenrobot:eventbus:3.0.0' }
类定义
1 public class EventBus { 2 3 static volatile EventBus defaultInstance; 4 5 private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder(); 6 private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>(); 7 8 private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; 9 private final Map<Object, List<Class<?>>> typesBySubscriber; 10 private final Map<Class<?>, Object> stickyEvents; 11 12 private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { 13 @Override 14 protected PostingThreadState initialValue() { 15 return new PostingThreadState(); 16 } 17 }; 18 19 private final HandlerPoster mainThreadPoster; 20 private final BackgroundPoster backgroundPoster; 21 private final AsyncPoster asyncPoster; 22 private final SubscriberMethodFinder subscriberMethodFinder; 23 private final ExecutorService executorService; 24 25 private final boolean throwSubscriberException; 26 private final boolean logSubscriberExceptions; 27 private final boolean logNoSubscriberMessages; 28 private final boolean sendSubscriberExceptionEvent; 29 private final boolean sendNoSubscriberEvent; 30 private final boolean eventInheritance; 31 32 private final int indexCount; 33 34 public static EventBus getDefault() { 35 if (defaultInstance == null) { 36 synchronized (EventBus.class) { 37 if (defaultInstance == null) { 38 defaultInstance = new EventBus(); 39 } 40 } 41 } 42 return defaultInstance; 43 } 44 45 public EventBus() { 46 this(DEFAULT_BUILDER); 47 } 48 49 EventBus(EventBusBuilder builder) { 50 subscriptionsByEventType = new HashMap<>(); 51 typesBySubscriber = new HashMap<>(); 52 stickyEvents = new ConcurrentHashMap<>(); 53 mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); 54 backgroundPoster = new BackgroundPoster(this); 55 asyncPoster = new AsyncPoster(this); 56 indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; 57 subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, 58 builder.strictMethodVerification, builder.ignoreGeneratedIndex); 59 logSubscriberExceptions = builder.logSubscriberExceptions; 60 logNoSubscriberMessages = builder.logNoSubscriberMessages; 61 sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; 62 sendNoSubscriberEvent = builder.sendNoSubscriberEvent; 63 throwSubscriberException = builder.throwSubscriberException; 64 eventInheritance = builder.eventInheritance; 65 executorService = builder.executorService; 66 } 67 }
注册(register)
当一个对象想要从EventBus接收事件时,只需在EventBus中进行注册自己,调用EventBus.getDefault().register(this)即可。register的实现如下:
1 public void register(Object subscriber) { 2 Class<?> subscriberClass = subscriber.getClass(); 3 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); 4 synchronized (this) { 5 for (SubscriberMethod subscriberMethod : subscriberMethods) { 6 subscribe(subscriber, subscriberMethod); 7 } 8 } 9 }
第3行,查找subscriber对应的类中所有接收EventBus事件的函数,然后依次调用subscribe函数注册这些所有查到的函数。subscribe的代码如下:
1 private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { 2 Class<?> eventType = subscriberMethod.eventType; 3 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); 4 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); 5 if (subscriptions == null) { 6 subscriptions = new CopyOnWriteArrayList<>(); 7 subscriptionsByEventType.put(eventType, subscriptions); 8 } else { 9 if (subscriptions.contains(newSubscription)) { 10 throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " 11 + eventType); 12 } 13 } 14 15 int size = subscriptions.size(); 16 for (int i = 0; i <= size; i++) { 17 if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { 18 subscriptions.add(i, newSubscription); 19 break; 20 } 21 } 22 23 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); 24 if (subscribedEvents == null) { 25 subscribedEvents = new ArrayList<>(); 26 typesBySubscriber.put(subscriber, subscribedEvents); 27 } 28 subscribedEvents.add(eventType); 29 30 if (subscriberMethod.sticky) { 31 if (eventInheritance) { 32 // Existing sticky events of all subclasses of eventType have to be considered. 33 // Note: Iterating over all events may be inefficient with lots of sticky events, 34 // thus data structure should be changed to allow a more efficient lookup 35 // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>). 36 Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet(); 37 for (Map.Entry<Class<?>, Object> entry : entries) { 38 Class<?> candidateEventType = entry.getKey(); 39 if (eventType.isAssignableFrom(candidateEventType)) { 40 Object stickyEvent = entry.getValue(); 41 checkPostStickyEventToSubscription(newSubscription, stickyEvent); 42 } 43 } 44 } else { 45 Object stickyEvent = stickyEvents.get(eventType); 46 checkPostStickyEventToSubscription(newSubscription, stickyEvent); 47 } 48 } 49 }
第3行,subscriber和subscriberMethod被封装成一个Subscription对象,Subscription描述了subscriber通过subscriberMethod对EventBus的一个事件订阅。
第4-21行,subscriptionsByEventType存储了<eventType, subscriptions>的映射关系,当分发事件时,使用该Map可以快速找到订阅了该事件的所有对象及其用于处理该事件的方法。subscriptions中的subscription,可能来自不同类的对象、同一类的不同对象、甚至同一个对象的不同方法,subscriptions以subscriberMethod.priority维护它们的降序顺序。对同一个对象的重复注册会导致第10行抛出EventBusException异常。
第23-28行,typesBySubscriber存储了<subscriber, subscribedEvents>的映射关系,当取消注册时,使用该Map可以快速找到该对象订阅的所有事件,或 判断该对象是否已经注册过了。
第30-48行,stickyEvents存储了<eventType, stickyEvent>的映射关系,与普通事件不同,除非显示移除,否则EventBus中总是保留该类事件的最近一次事件实例。当subscriberMethod.sticky为true,从stickyEvents中查找eventType对应的stickyEvent发送给该对象。若eventInheritance为true,查找stickyEvents中所有eventType及其子类的事件进行发送。
取消注册(unregister)
当一个类不再需要接收EventBus时,它需要在EventBus中取消注册,即调用EventBus.getDefault().unregister(this)。这很重要,在实际开发中,很多内存泄漏问题都是由于注册之后没有取消注册导致的。unregister的实现如下:
1 public synchronized void unregister(Object subscriber) { 2 List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); 3 if (subscribedTypes != null) { 4 for (Class<?> eventType : subscribedTypes) { 5 unsubscribeByEventType(subscriber, eventType); 6 } 7 typesBySubscriber.remove(subscriber); 8 } else { 9 Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass()); 10 } 11 }
使用typesBySubscriber查找subscriber订阅了的所有事件类型,依次调用unsubcribeByEventType函数取消subscriber对每个eventType的订阅,然后将subscriber从typesBySubscriber中移除。unsubcribeByEventType的实现如下:
1 private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { 2 List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); 3 if (subscriptions != null) { 4 int size = subscriptions.size(); 5 for (int i = 0; i < size; i++) { 6 Subscription subscription = subscriptions.get(i); 7 if (subscription.subscriber == subscriber) { 8 subscription.active = false; 9 subscriptions.remove(i); 10 i--; 11 size--; 12 } 13 } 14 } 15 }
使用subscriptionsByEventType查找eventType对应的subscriptions,然后移除subscriptions中所有subscription.subscriber==subscriber的subscription,并将subscription.active置为false。
总结
EventBus中与事件分发相关的底层实现主要涉及三个Map:
- subscriptionsByEventType--<eventType, subscriptions>,主要用于事件分发,用于快速找到event的订阅者集合;
- typesBySubscriber--<subscriber, eventType>,主要用于取消注册,用于快速查找对象订阅的事件类集合;
- stickyEvents保存了stickyEvent的最近一次事件实例。