1. 程式人生 > >Guava源碼學習(五)EventBus

Guava源碼學習(五)EventBus

mmu 類圖 null find sync fab cnblogs table array

基於版本:Guava 22.0

Wiki:EventBus

0. EventBus簡介

提供了發布-訂閱模型,可以方便的在EventBus上註冊訂閱者,發布者可以簡單的將事件傳遞給EventBus,EventBus會自動將事件傳遞給相關聯的訂閱者。

支持同步/異步模式。

只能用於線程間通信。

1. EventBus類圖

技術分享

EventBus是同步實現

AsyncEventBus是異步實現

2. 代碼實例

        EventBus eventBus = new EventBus();
        
        eventBus.register(new Object() {
            @Subscribe
            
public void listen(Object subReport) throws Exception { System.out.println("receive object event!"); } @Subscribe public void listen(Integer subReport) throws Exception { System.out.println("receive integer event!"); } }); eventBus.post(Integer.valueOf(
1));

這段代碼的輸出如下:

receive integer event!
receive object event!

3. EventBus.register()

EventBus.register
  /**
   * Registers all subscriber methods on {@code object} to receive events.
   *
   * @param object object whose subscriber methods should be registered.
   */
  public void register(Object object) {
    subscribers.register(object);
  }


SubscriberRegistry.register
  
/** * Registers all subscriber methods on the given listener object. */ void register(Object listener) { Multimap<Class<?>, Subscriber> listenerMethods = findAllSubscribers(listener);//獲取傳入的listener中含有的所有的監聽者 for (Map.Entry<Class<?>, Collection<Subscriber>> entry : listenerMethods.asMap().entrySet()) { Class<?> eventType = entry.getKey();//監聽的事件類型 Collection<Subscriber> eventMethodsInListener = entry.getValue();//對應的監聽器本身 CopyOnWriteArraySet<Subscriber> eventSubscribers = subscribers.get(eventType); if (eventSubscribers == null) { CopyOnWriteArraySet<Subscriber> newSet = new CopyOnWriteArraySet<Subscriber>(); eventSubscribers = MoreObjects.firstNonNull(subscribers.putIfAbsent(eventType, newSet), newSet); } eventSubscribers.addAll(eventMethodsInListener); } } /** * Returns all subscribers for the given listener grouped by the type of event they subscribe to. 分析傳入的對象,遍歷其中所有含有Subscribe註解而且只含有一個參數的方法,然後將其包裝成監聽者並返回。 */ private Multimap<Class<?>, Subscriber> findAllSubscribers(Object listener) { Multimap<Class<?>, Subscriber> methodsInListener = HashMultimap.create(); Class<?> clazz = listener.getClass(); for (Method method : getAnnotatedMethods(clazz)) {//getAnnotatedMethods方法最終會調用到下面的SubscriberRegistry.getAnnotatedMethodsNotCached方法,這個方法會用反射處理傳入的clazz及其所有的父類,提取出含有Subscribe註解並且有且只有一個參數的方法 Class<?>[] parameterTypes = method.getParameterTypes(); Class<?> eventType = parameterTypes[0];//獲取這個方法的唯一參數的Class methodsInListener.put(eventType, Subscriber.create(bus, listener, method));//將EventBus,監聽者對象,監聽者方法包裝一下並放入map,後續觸發事件的時候會用到 } return methodsInListener; } SubscriberRegistry.getAnnotatedMethodsNotCached private static ImmutableList<Method> getAnnotatedMethodsNotCached(Class<?> clazz) { Set<? extends Class<?>> supertypes = TypeToken.of(clazz).getTypes().rawTypes();//連clazz的父類也會處理 Map<MethodIdentifier, Method> identifiers = Maps.newHashMap(); for (Class<?> supertype : supertypes) { for (Method method : supertype.getDeclaredMethods()) { if (method.isAnnotationPresent(Subscribe.class) && !method.isSynthetic()) {//含有Subscribe註解,而且不是合成的方法 // TODO(cgdecker): Should check for a generic parameter type and error out Class<?>[] parameterTypes = method.getParameterTypes(); checkArgument( parameterTypes.length == 1, "Method %s has @Subscribe annotation but has %s parameters." + "Subscriber methods must have exactly 1 parameter.", method, parameterTypes.length);//方法必須有且只有一個參數 MethodIdentifier ident = new MethodIdentifier(method); if (!identifiers.containsKey(ident)) { identifiers.put(ident, method); } } } } return ImmutableList.copyOf(identifiers.values()); }

Guava源碼學習(五)EventBus