Guava中EventBus的使用和详解
来源:互联网 发布:linux less命令 退出 编辑:程序博客网 时间:2024/04/28 11:31
概述
EventBus是Google Guava库中一个常用的组件。他使用了设计模式中的Observer(观察者)模式,实现了一个publish/subscribe模型的消息总线,简化了各组件之间之间的通信。
Observer模式是比较常见和简单的设计模式之一,在JDK中,提供Observable和Observer这两个类可以快速使用。EventBus是Google在Guava中所实现的一个更加优雅和间的方案。更为重要的是,利用EventBus可以将事件发布者和事件订阅者解耦。发布者不再需要知道有那些订阅者,事件的派发由EventBus完成。
EventBus的基本用法:
在传统的Android程序开发中,实现Observer模式往往会为被观察对象定义一个Listener接口,而观察者实现一个继承此接口的对象作为Listener并注册给被观察对象。而使用Guava中的EventBus后,如果想订阅消息,并不需要再去继承Observable所指定的接口。之需要在制定的方法中加上@Subscribe注解即可。
观察者:
import com.google.common.eventbus.EventBus;public class TestObserver {private EventBus = new Event("TestEventBus");EventBus.register(this);private TestObservable mObservable;@Subscribepublic void onTestEvent(TestEvent event) {// implement event handling here}}
public class TestObservable {private EventBus mEventBus;public void setEventBus(EventBus event_bus) {mEventBus = event_bus;}public void postSomeEvent() {if (mEventBus != null) {mEventBus.post(new TestEvent());}}}
public class TestEvent{}
- 自定义一个消息类型
- 创建一个EventBus,并将观察者注册在这个EventBus中,并实现处理此消息类型的函数,以注解@Subscribe修饰。
- 被观察者获得EventBus对象,当需要发布消息的时候,向此EventBus对象发布Event。观察者便会对应的消息处理函数中收到此消息。
EventBus的代码分析
Register函数
首先来分析EventBus类中的register函数:
public void register(Object object) { Multimap<Class<?>, EventSubscriber> methodsInListener = finder.findAllSubscribers(object); subscribersByTypeLock.writeLock().lock(); try { subscribersByType.putAll(methodsInListener); } finally { subscribersByTypeLock.writeLock().unlock(); } }methodsInListener中会根据@Subscribe的注解查找所传入对象的EventHandler,并将事件类型与EventSubscriber的映射保留在subscribersByType对象中。
再来看AnnotatedSubscriberFinder中的findAllSubscribers方法:
@Override public Multimap<Class<?>, EventSubscriber> findAllSubscribers(Object listener) { Multimap<Class<?>, EventSubscriber> methodsInListener = HashMultimap.create(); Class<?> clazz = listener.getClass(); for (Method method : getAnnotatedMethods(clazz)) { Class<?>[] parameterTypes = method.getParameterTypes(); Class<?> eventType = parameterTypes[0]; EventSubscriber subscriber = makeSubscriber(listener, method); methodsInListener.put(eventType, subscriber); } return methodsInListener; }上面代码的内容就是通过反射读取Subscriber对象中带有@Subscribe注解的方法,并使用makeSubscriber将Subscriber对象和它的带@Subscribe对象的method对象封装成EventSubscriber标准事件处理对象:
private static EventSubscriber makeSubscriber(Object listener, Method method) { EventSubscriber wrapper; if (methodIsDeclaredThreadSafe(method)) { wrapper = new EventSubscriber(listener, method); } else { wrapper = new SynchronizedEventSubscriber(listener, method); } return wrapper; }
Post函数:
public void post(Object event) { Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass()); boolean dispatched = false; for (Class<?> eventType : dispatchTypes) { subscribersByTypeLock.readLock().lock(); try { Set<EventSubscriber> wrappers = subscribersByType.get(eventType); if (!wrappers.isEmpty()) { dispatched = true; for (EventSubscriber wrapper : wrappers) { enqueueEvent(event, wrapper); } } } finally { subscribersByTypeLock.readLock().unlock(); } } if (!dispatched && !(event instanceof DeadEvent)) { post(new DeadEvent(this, event)); } dispatchQueuedEvents(); }
void enqueueEvent(Object event, EventSubscriber subscriber) { eventsToDispatch.get().offer(new EventWithSubscriber(event, subscriber)); }最后通过dispatchQueuedEvents()处理队列中的事件:
void dispatchQueuedEvents() { // don't dispatch if we're already dispatching, that would allow reentrancy // and out-of-order events. Instead, leave the events to be dispatched // after the in-progress dispatch is complete. if (isDispatching.get()) { return; } isDispatching.set(true); try { Queue<EventWithSubscriber> events = eventsToDispatch.get(); EventWithSubscriber eventWithSubscriber; while ((eventWithSubscriber = events.poll()) != null) { dispatch(eventWithSubscriber.event, eventWithSubscriber.subscriber); } } finally { isDispatching.remove(); eventsToDispatch.remove(); } }dispatch的代码如下:
void dispatch(Object event, EventSubscriber wrapper) { try { wrapper.handleEvent(event); } catch (InvocationTargetException e) { try { subscriberExceptionHandler.handleException( e.getCause(), new SubscriberExceptionContext( this, event, wrapper.getSubscriber(), wrapper.getMethod())); } catch (Throwable t) { // If the exception handler throws, log it. There isn't much else to do! Logger.getLogger(EventBus.class.getName()).log(Level.SEVERE, String.format( "Exception %s thrown while handling exception: %s", t, e.getCause()), t); } } }wrapper.hanleEvent()反射调用事件处理的方法:
public void handleEvent(Object event) throws InvocationTargetException { checkNotNull(event); try { method.invoke(target, new Object[] { event }); } catch (IllegalArgumentException e) { throw new Error("Method rejected target/argument: " + event, e); } catch (IllegalAccessException e) { throw new Error("Method became inaccessible: " + event, e); } catch (InvocationTargetException e) { if (e.getCause() instanceof Error) { throw (Error) e.getCause(); } throw e; } }
0 0
- Guava中EventBus的使用和详解
- EventBus的详解和使用
- EventBus的使用详解和封装
- EventBus的使用详解
- EventBus的使用详解
- Eventbus的使用详解
- 使用Guava的eventbus完成异步事件的简单例子
- Guava中Cache的使用
- EventBus(Guava)
- Guava中EventBus并发处理事件
- EventBus的使用详解(一)--初步使用EventBus
- EventBus的使用详解(一)--初步使用EventBus
- Android中EventBus的使用
- Android中EventBus的使用
- Android中EventBus的使用
- Android中EventBus使用详解(一)
- droid中EventBus使用详解(二)
- EventBus的使用和学习
- 初步感受一下非阻塞的socket
- Myeclipse 10 for mac 安装过程及myeclipse 10 for mac 破解版下载
- JAVA学习笔记32——hashCode和equals方法+set接口
- Context-----Activity,Application之间的交流使者
- jquer ajax webservice 500 Internal Server Erro
- Guava中EventBus的使用和详解
- 谷歌是如何做代码审查的
- 实时监听输入框值变化的完美方案:oninput & onpropertychange
- ubuntu 创建和删除文件夹
- WV.45-简单成绩统计
- Linux解压命令
- JTable学习
- 当代IT大牛
- BLE 协议栈 之"消息传递""事件触发"谁与争锋