美文网首页
Android开发开源控件之EventBus

Android开发开源控件之EventBus

作者: DanieX | 来源:发表于2016-05-31 11:45 被阅读497次

    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. 基本概念:

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

    • Event
    • Subscriber
    • Publisher
      下面这幅图说明了这几者之间的关系:
    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 高效、简洁和极易入门的特性让人着迷。有了它,妈妈再也不会担心我写出像一坨翔一样的代码了。

    相关文章

      网友评论

          本文标题:Android开发开源控件之EventBus

          本文链接:https://www.haomeiwen.com/subject/owbtrttx.html