Guava源碼學習(五)EventBus
阿新 • • 發佈:2017-08-04
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() { @Subscribepublic 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