概述
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;
@Subscribe
public 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;
}
}