Otto源码初探

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对象,作为程序组件之间的通信桥梁,实现了程序组件之间的解耦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值