Android开发开源控件之EventBus

2016-05-31  本文已影响497人  DanieX

EventBus 简介

EventBus 直译过来就是事件总线,熟悉计算机原理的人一定很熟悉总线的概念,所有设备都连接到总线上,然后在总线控制器上注册一个地址,当接收到消息的时候,总线控制器就从自己地址列表中取出该地址,把这个消息转发给某个设备。所以这个是个典型的应用了发布-订阅设计模式的开源库,它使用起来非常方便,同时使代码简洁,减少了模块之间的耦合。

EventBus

使用方法

1. 加入到你的项目中

Gradle:

 compile 'org.greenrobot:eventbus:3.0.0'

Maven:

<dependency>
    <groupId>org.greenrobot</groupId>
    <artifactId>eventbus</artifactId>
    <version>3.0.0</version>
</dependency>

或者从Maven Center下载。

2. 基本概念:

在使用之前,有几个重要基本概念需要理解:

EventBus 架构图

索引加速

我们在前面留了一个悬念,说EventBus 用了一项黑科技。上面的这个架构图中的右侧部分就是这项黑科技。使用索引加速后,能极大的提高索引速度,下面这张图来自作者的博客。

性能对比

应用索引加速

前面介绍了这个黑科技多么牛X,相信你已经跃跃欲试了。那我们就开始来介绍怎么使用吧!

  1. 因为注解解析依赖于android-apt-plugin,所以我们首先在项目的 gradle 的 dependencies 中加入 apt 编译插件:
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
  1. 在 App 的 build.gradle 中应用apt插件,并设置apt生成的索引的包名和类名,eventBusIndex的值是由你指定的,编译成功后就会生成一个 MyEventBusIndex.java 文件:
apply plugin: 'com.neenbedankt.android-apt'
apt {
    arguments {
        eventBusIndex "com.daniex.demoApp.MyEventBusIndex"
    }
}
  1. 接着我们在 App 的 dependencies 中引入 EventBusAnnotationProcessor :
apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
  1. 编译一次,就会在{ApplicationName}/build/generated/apt/{packagename} 目录下生成 MyEventBusIndex.java 。要应用我们刚刚生成的index,我们可以通过以下方法:
EventBus mEventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();

如果你不想每次都写这么冗长的代码,你可以在你的 application 类中把我们刚刚生成的索引设置为默认的:

EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();

在其他地方我们可以像平常一样用 EventBus.getDefault() 来获取默认实例了。
下面就是通过索引加速生成的代码:

/** This class is generated by EventBus, do not edit. */
public class EventBusIndex implements SubscriberInfoIndex {
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;

    static {
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();

        putIndex(new SimpleSubscriberInfo(com.dili.posandroid.activity.ChooseCategoryActivity.class, true,
                new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onSelcted", com.dili.posandroid.event.CategorySelectEvent.class),
        }));

    }

    private static void putIndex(SubscriberInfo info) {
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }

    @Override
    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }
}

生成索引加速的原理,我们必须的看 EventBusAnnotationProcessor.java 源码:

@SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe")
@SupportedOptions(value = {"eventBusIndex", "verbose"})
public class EventBusAnnotationProcessor extends AbstractProcessor {
    /** Found subscriber methods for a class (without superclasses). 被注解表示的方法信息 */ 
    private final ListMap<TypeElement, ExecutableElement> methodsByClass = new ListMap<>();
    private final Set<TypeElement> classesToSkip = new HashSet<>(); // checkHasErrors检查出来的异常方法

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
        Messager messager = processingEnv.getMessager();
        try {
            String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX);
            if (index == null) { // 如果没有在gradle中配置apt的argument,编译就会在这里报错
                messager.printMessage(Diagnostic.Kind.ERROR, "No option " + OPTION_EVENT_BUS_INDEX +
                        " passed to annotation processor");
                return false;
            }
            /** ... */
            collectSubscribers(annotations, env, messager); // 根据注解拿到所有订阅者的回调方法信息
            checkForSubscribersToSkip(messager, indexPackage); // 筛掉不符合规则的订阅者
            if (!methodsByClass.isEmpty()) {
                createInfoIndexFile(index); // 生成索引类
            } 
            /** 打印错误 */
    }

    /** 下面这些方法就不再贴出具体实现了,我们了解它们的功能就行 */
    private void collectSubscribers // 遍历annotations,找出所有被注解标识的方法,以初始化methodsByClass
    private boolean checkHasNoErrors // 过滤掉static,非public和参数大于1的方法
    private void checkForSubscribersToSkip // 检查methodsByClass中的各个类,是否存在非public的父类和方法参数
    /** 下面这三个方法会把methodsByClass中的信息写到相应的类中 */
    private void writeCreateSubscriberMethods
    private void createInfoIndexFile
    private void writeIndexLines
}

结语

每当我们看到项目中 activity 之间,看到activity 跟 Fragment 、activity 跟adapter之间互相调用,强制转换,高度耦合,像一团乱麻的时候,心里总是忍不住骂一句:WTF ! EventBus 高效、简洁和极易入门的特性让人着迷。有了它,妈妈再也不会担心我写出像一坨翔一样的代码了。

上一篇下一篇

猜你喜欢

热点阅读