• Android中注解处理器系列之-简单使用


    概念

    APT(Annotation Processing Tool)即注解处理器,是一种处理Java源代码的工具。它可以在编译期对注解进行处理,从而生成一些额外的代码或者进行一些额外的操作。相比于运行期注解处理,APT可以更加高效地处理注解,因为它是在编译期进行处理的。

    Android开发中,APT技术常常用于自动生成代码,比如生成View的findViewById方法、生成Activity的Intent参数传递代码、生成注入框架等。通过APT技术,可以大大提高代码的开发效率和可读性。常用的APT框架有ButterKnife、Dagger、EventBus等。
    APT 在 Java 编译器完成第一次编译后,对生成的 Java 文件进行再次编译和处理,可以生成新的 Java 代码和资源文件,或者生成其他需要的文件,如配置文件、HTML、XML 等。

    APT 的处理时机是在 Java 源代码编译时。在编译 Java 代码时,编译器会检查源代码中是否包含注解,并且会扫描所有注解处理器类,并执行这些注解处理器类中的 process() 方法,从而生成新的 Java 代码或者其他文件。由于 APT 的处理时机是在 Java 源代码编译时,因此需要在编译器中进行相关配置,以便在编译时调用注解处理器。通常需要在构建工具中进行配置,例如在 Gradle 中使用 apt 插件。

    创建模块

    首先我们创建两个java项目(注意必须为两个java模块,我之前因为创建模块错误,导致代码功能根本跑不通),分别为为compiler与annotations,其中annotations为自定义注解模块,compiler为助力器处理代码模块。

    模块结构

    创建依赖关系

    app依赖:

    implementation project(path: ':annotations')
    //注意此处的依赖关键词
    annotationProcessor  project(path: ':compiler')
    
    • 1
    • 2
    • 3

    compiler依赖:

    //这里用到了spi机制
    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
    compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
    
    implementation project(path: ':annotations')
    
    • 1
    • 2
    • 3
    • 4
    • 5

    创建process类(注解处理节点)

    注意我们最终工作的地方就是以下process的方法内,在此方法中我们可以生成我们想生成的文件,并通过JavaWriter将文件写到本地,其实写文件就是拼接字符串的过程。

    注意此类文件是在compiler中创建的

    /**
     * 注解处理器,用来生成代码的
     * 使用前需要注册
     * 此代码是在电脑中执行的。
     */
    @AutoService(Processor.class)
    public class AnnotationsCompiler extends AbstractProcessor {
        //1.支持的版本
        @Override
        public SourceVersion getSupportedSourceVersion() {
            //选择最新的版本
            return SourceVersion.latestSupported();
        }
    
        //2.能用来处理哪些注解。
        @Override
        public Set<String> getSupportedAnnotationTypes() {
            Set<String> types = new HashSet<>();
            types.add(BindView.class.getCanonicalName());
            return types;
        }
    
        //3.定义一个用来生成APT目录下面的文件的对象
        Filer filer;
    
        @Override
        public synchronized void init(ProcessingEnvironment processingEnvironment) {
            super.init(processingEnvironment);
            filer = processingEnvironment.getFiler();
        }
    
    
        /**
         * 在这个方法中生成文件。
         *
         * @param set
         * @param roundEnvironment
         * @return
         */
        @Override
        public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
    
    
            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,"test-------------"+set);
            //获取APP中所有用到了BindView注解的对象
            Set<? extends Element> elementsAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(BindView.class);
    
    //        TypeElement//类
    //        ExecutableElement//方法
    //          VariableElement//属性
            //开始对elementsAnnotatedWith进行分类
            Map<String, List<VariableElement>> map = new HashMap<>();
            for (Element element : elementsAnnotatedWith) {
                VariableElement variableElement = (VariableElement) element;
                String activityName = variableElement.getEnclosingElement().getSimpleName().toString();
                Class aClass = variableElement.getEnclosingElement().getClass();
                List<VariableElement> variableElements = map.get(activityName);
                if (variableElements == null) {
                    variableElements = new ArrayList<>();
                    map.put(activityName, variableElements);
                }
                variableElements.add(variableElement);
            }
         
    
    
            return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    创建注解

    这里在annotations中随便创建了一个注解,用来调试用。(如果注解的使用方法不会用的建议网上搜索相关知识来学习)。

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface BindView {
        int value();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    测试使用

    在测试Activity中使用注解注释TextView。

    public class MainActivity extends AppCompatActivity {
        //注解
        @BindView(R.id.main_tv)
        TextView textView;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    点击as,进行构建工程,我们可以在build中看见我们打印的日志信息。

    test-------------[com.example.annotation.BindView]
    
    • 1

    目前此文章知识讲解apt的简单入门使用。
    后面讲解apt的实践以及源码解读。

  • 相关阅读:
    基于Java实现EsriJson、GeoJson互相转换方法
    每日一题——LeetCode1646.获取生成数组中的最大值
    mysql 事务 Read Uncommitted
    排序——手撕快排
    吃透Redis(七):网络框架篇-redis 6.0 IO多线程原子性保证
    “index“ should always be multi-word
    ResNet 原理与代码复现
    LQ0161 九数分三组【枚举+置换】
    【JavaWeb】JSP技术详解
    webpack优化策略
  • 原文地址:https://blog.csdn.net/chendeshan330/article/details/126715839