register 过程:
register 接受一个Object实例作为参数,然后把该实例的producer和subscriber方法扫描出来。
从代码注释可知, 如果你在订阅一个事件类型时, 这个类型已经注册了producer, 那么EventBus会立即调用producer产生事件向 刚注册的 subscribers发布。
另外,一个事件类型只能对应一个producer, 否则抛出异常。
还有就是要理解 ConcurrentMap 的 putIfAbsent 方法:如果指定的key-value 不存在则相当于put 操作, 否则相当于get 操作。
/**
* Registers all handler methods on {@code object} to receive events and producer methods to provide events.
* <p>
* If any subscribers are registering for types which already have a producer they will be called immediately
* with the result of calling that producer.
* <p>
* If any producers are registering for types which already have subscribers, each subscriber will be called with
* the value from the result of calling the producer.
*
* @param object object whose handler methods should be registered.
* @throws NullPointerException if the object is null.
*/
public void register(Object object) {
...
enforcer.enforce(this);
//提取 producer
Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);
for (Class<?> type : foundProducers.keySet()) {
final EventProducer producer = foundProducers.get(type);
EventProducer previousProducer = producersByType.putIfAbsent(type, producer);
//checking if the previous producer existed
//一个事件类型只能有一个生产者
if (previousProducer != null) {
throw new IllegalArgumentException("Producer method for type " + type + " found on type " + producer.target.getClass()
+ ", but already registered by type " + previousProducer.target.getClass() + ".");
}
Set<EventHandler> handlers = handlersByType.get(type);
if (handlers != null && !handlers.isEmpty()) {
for (EventHandler handler : handlers) {
dispatchProducerResultToHandler(handler, producer);
}
}
}
// 提取 subscriber
Map<Class<?>, Set<EventHandler>> foundHandlersMap = handlerFinder.findAllSubscribers(object);
for (Class<?> type : foundHandlersMap.keySet()) {
Set<EventHandler> handlers = handlersByType.get(type);
if (handlers == null) {
//concurrent put if absent
Set<EventHandler> handlersCreation = new CopyOnWriteArraySet<EventHandler>();
handlers = handlersByType.putIfAbsent(type, handlersCreation);
if (handlers == null) {
handlers = handlersCreation;
}
}
final Set<EventHandler> foundHandlers = foundHandlersMap.get(type);
handlers.addAll(foundHandlers);
}
//对于新注册的订阅者,如果有producer,则立即向订阅者发布最新事件
for (Map.Entry<Class<?>, Set<EventHandler>> entry : foundHandlersMap.entrySet()) {
Class<?> type = entry.getKey();
EventProducer producer = producersByType.get(type);
if (producer != null && producer.isValid()) {
Set<EventHandler> foundHandlers = entry.getValue();
for (EventHandler foundHandler : foundHandlers) {
if (!producer.isValid()) {
break;
}
if (foundHandler.isValid()) {
dispatchProducerResultToHandler(foundHandler, producer);
}
}
}
}
}
post 过程:
将一个事件向所有的subscribers发布,如果某个handler发生异常将被无视 :D
如果一个事件没有相应的subscriber来处理,那么这个事件将被包装成 DeadEvent 并重新发布;
/**
* Posts an event to all registered handlers. This method will return successfully after the event has been posted to
* all handlers, and regardless of any exceptions thrown by handlers.
*
* <p>If no handlers have been subscribed for {@code event}'s class, and {@code event} is not already a
* {@link DeadEvent}, it will be wrapped in a DeadEvent and reposted.
*
* @param event event to post.
* @throws NullPointerException if the event is null.
*/
public void post(Object event) {
if (event == null) {
throw new NullPointerException("Event to post must not be null.");
}
enforcer.enforce(this);
Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());
boolean dispatched = false;
for (Class<?> eventType : dispatchTypes) {
Set<EventHandler> wrappers = getHandlersForEventType(eventType);
if (wrappers != null && !wrappers.isEmpty()) {
dispatched = true;
for (EventHandler wrapper : wrappers) {
enqueueEvent(event, wrapper);
}
}
}
if (!dispatched && !(event instanceof DeadEvent)) {
post(new DeadEvent(this, event));
}
dispatchQueuedEvents();
}
跨线程问题
在register 和 post 方法中 都有一个enforcer 变量,它是ThreadEnforcer的实现, 用来限制register、post等方法调用的线程(一般只能在主线程中调用) ,你也可以实现自己的ThreadEnforcer来改变折中策略。
另外eventToDispatch 以及 isDispatching 变量都使用了ThreadLocal , 这些也为你实现自己的ThreadEnforcer策略提供了支持,同时还可以看出,Otto是不能跨线程发布事件的, 如果确实需要这样做,要借助线程的Looper 或 AsyncTask 来实现。
/** Thread enforcer for register, unregister, and posting events. */
private final ThreadEnforcer enforcer;
/** Queues of events for the current thread to dispatch. */
private final ThreadLocal<ConcurrentLinkedQueue<EventWithHandler>> eventsToDispatch = new ThreadLocal<ConcurrentLinkedQueue<EventWithHandler>>() {
@Override protected ConcurrentLinkedQueue<EventWithHandler> initialValue() {
return new ConcurrentLinkedQueue<EventWithHandler>();
}
};
/** True if the current thread is currently dispatching an event. */
private final ThreadLocal<Boolean> isDispatching = new ThreadLocal<Boolean>() {
@Override protected Boolean initialValue() {
return false;
}
};