Otto源码初探
Otto是面向Android平台的事件总线框架,官网这样介绍:
An enhanced event bus with emphasis on Android support
Otto有利于程序组件之间解耦,简化组件通信逻辑。相关网站:otto主页,github地址
Otto框架使用
Otto框架使用简单,实例化Bus对象,发送事件对象即可:
Bus bus = new Bus();
bus.post(new AnswerAvailableEvent(42));
Otto使用对象类型识别事件,监听事件需要@Subscribe注解方法,并用register注册方法所在对象。
@Subscribe public void answerAvailabl(AnswerAvailableEvent event) {
// 响应代码
}
// 注册事件
bus.register(this);
Otto还提供了@Produce注解方法生成事件对象。同样,@Produce方法实例对象也需要使用register注册。
Bus类
Otto实现原理并不复杂,Bus是主要操作类,提供register,unregister,post方法,其构造函数如下:
Bus(ThreadEnforcer enforcer, String identifier, HandlerFinder handlerFinder){
this.enforcer = enforcer;
this.identifier = identifier;
this.handlerFinder = handlerFinder;
}
Bus(){
this(ThreadEnforcer.MAIN, DEFAULT_IDENTIFIER, HandlerFinder.ANNOTATED);
}
ThreadEnforcer定义enfore方法,代表线程限制方式,默认为ThreadEnforcer.MAIN对象,当前线程不为主线程是抛出异常。在register/unregister/post方法默认需要在主线程中进行。identifier为Bus对象的标识符。HandlerFinder定义了findAllProducers和findAllSubscribers方法,默认为HandlerFinder.ANNOTATED对象,调用AnnotatedHandlerFinder静态方法,对传入对象查找所有@Produce和@Subscribe的方法。
register/unregister
Otto使用register方法注册@Produce和@Subscribe的方法。Bus中分别对应两个数据结构producersByType和handlersByType,其定义如下:
//事件处理方法数据结构,event类型为索引
private final ConcurrentMap<Class<?>, Set<EventHandler>> handlersByType = new ConcurrentHashMap();
//pruduce方法数据结构,event类型为索引
private final ConcurrentMap<Class<?>, EventProducer> producersByType = new ConcurrentHashMap();
register方法把注册对象的@Produce和@Subscribe的方法转换并放入producersByType和handlersByType,而unregister方法则把所注册的方法删除,防止内存泄漏。其中,EventHandler为事件处理方法的数据结构,EventProducer为produce方法的数据结构。register方法实现如下:
public void register(Object object) {
if (object == null) {
throw new NullPointerException("Object to register must not be null.");
}
enforcer.enforce(this); // 线程限制
Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object); // 查找Produce方法
for (Class<?> type : foundProducers.keySet()) {
final EventProducer producer = foundProducers.get(type);
EventProducer previousProducer = producersByType.putIfAbsent(type, producer); // 保存Produce方法
// 判断Produce方法是否已存在
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); // 运行Produce方法注册事件
}
}
}
Map<Class<?>, Set<EventHandler>> foundHandlersMap = handlerFinder.findAllSubscribers(object); // 查找Subscribe方法
for (Class<?> type : foundHandlersMap.keySet()) {
Set<EventHandler> handlers = handlersByType.get(type);
if (handlers == null) {
Set<EventHandler> handlersCreation = new CopyOnWriteArraySet<EventHandler>();
handlers = handlersByType.putIfAbsent(type, handlersCreation); // 保存Subscribe方法
if (handlers == null) {
handlers = handlersCreation;
}
}
final Set<EventHandler> foundHandlers = foundHandlersMap.get(type);
if (!handlers.addAll(foundHandlers)) {
throw new IllegalArgumentException("Object already registered.");
}
}
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); // 若事件类型已注册则运行Subscribe方法
}
}
}
}
}
从代码实现可以看出,当调用register时,若事件类型已经注册,则会立即执行事件处理方法。
事件投递
Otto使用post投递事件,若事件类型已注册,则利用反射运行所有事件处理方法,代码如下:
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)); // 若没有注册事件处理方法,则用DeadEvent封装event重新投递事件
}
// 从队列中运行所有事件处理方法
dispatchQueuedEvents();
}
总结
总体来看,Otto利用贯穿程序生命周期的Bus对象,作为程序组件之间的通信桥梁,实现了程序组件之间的解耦。