美文网首页
Android使用AbstractProcessor生成类和方法

Android使用AbstractProcessor生成类和方法

作者: 放羊娃华振 | 来源:发表于2019-12-03 22:31 被阅读0次

    概述

    很多的Android或者java的框架都使用动态生成代码的技术。例如Android的ARouter,Butterknife等。今天我们简单实现是通过AbstractProcessor生成java文件。

    实现

    1.创建一个Android工程,工程结构如下:
    image.png
    2.build.gradle的内容如下:
    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 26
        buildToolsVersion "26.0.3"
        defaultConfig {
            applicationId "com.stormful.android.abstractprocessordemo"
            minSdkVersion 15
            targetSdkVersion 26
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.android.support:appcompat-v7:26.1.0'
        //引入AbstractProcessor工程
        annotationProcessor project(':compiler')
    }
    
    3.创建compiler依赖库,这个库的作用就是生成java代码。
    image.png
    4.编写CompilerProcessor的代码,代码有注释,我就不再重复描述。
    /**
     * 使用AbstractProcessor生成代码
     */
    @AutoService(Processor.class)
    public class CompilerProcessor extends AbstractProcessor {
    
        //文件相关的辅助类
        private Filer mFiler;
        //元素相关的辅助类
        private Elements mElementUtils;
        //日志相关的辅助类
        private Messager mMessager;
    
        @Override
        public synchronized void init(ProcessingEnvironment processingEnvironment) {
            super.init(processingEnvironment);
            mInit();
        }
    
        /**
         * 初始化常用对象
         */
        private void mInit() {
            mElementUtils = processingEnv.getElementUtils();
            mMessager = processingEnv.getMessager();
            mFiler = processingEnv.getFiler();
            printLog("AbstractProcessor:" + "mInit");
        }
    
        @Override
        public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
            printLog("AbstractProcessor:" + "process");
    
            //生成一个空的类
            generateEmptyClass();
    
            //生成一个有方法的类
            generateMehthodClass();
    
            return true;
        }
    
        /**
         * 这里必须指定,这个注解处理器是注册给哪个注解的。改方法不执行可能导致process方法不会执行
         * 注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。
         * 换句话说,在这里定义你的注解处理器注册到哪些注解上。
         *
         * @return
         */
        @Override
        public Set<String> getSupportedAnnotationTypes() {
            Set<String> types = new LinkedHashSet<>();
            types.add(Override.class.getCanonicalName());
            return types;
        }
    
    
        /**
         * 打印log
         *
         * @param msg  信息
         * @param args 参数
         */
        private void printLog(String msg, Object... args) {
            //printLog("Generate file failed, reason: %s", "init");
            mMessager.printMessage(Diagnostic.Kind.NOTE, String.format(msg, args));
        }
    
        /**
         * 打印log
         *
         * @param msg 信息
         */
        private void printLog(String msg) {
            //printLog("init");
            mMessager.printMessage(Diagnostic.Kind.NOTE, msg);
        }
    
    
        /**
         * 创建一个空的java类
         */
        private void generateEmptyClass() {
            //创建类
            TypeSpec generateEmptyClass = TypeSpec.classBuilder("GenerateEmptyClass")
                    .addModifiers(Modifier.PUBLIC)
                    .build();
            //创建类存放的包名
            JavaFile javaFile = JavaFile.builder("com.stormful.android.abstractprocessordemo", generateEmptyClass).build();
    
            //创建类
            try {
                javaFile.writeTo(mFiler);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private void generateMehthodClass() {
    
            String className = "GenerateMethodClass";
            String text = "我是返回值,在getTextMethod方法中";
    
            StringBuilder builder = new StringBuilder()
                    .append("package com.autotestdemo.maomao.autotestdemo.auto;\n\n")
                    .append("public class ")
                    .append(className)
                    .append(" {\n\n") // open class
                    .append("\tpublic String getTextMethod() {\n") // open method
                    .append("\t\treturn \"");
    
            // this is appending to the return statement
            builder.append(text).append(" !");
    
    
            builder.append("\";\n") // end returne
                    .append("\t}\n") // close method
                    .append("}\n"); // close class
    
    
            try { // write the file
                JavaFileObject source = mFiler.createSourceFile("com.stormful.android.abstractprocessordemo." + className);
                Writer writer = source.openWriter();
                writer.write(builder.toString());
                writer.flush();
                writer.close();
            } catch (IOException e) {
                // Note: calling e.printStackTrace() will print IO errors
                // that occur from the file already existing after its first run, this is normal
                e.printStackTrace();
            }
        }
    }
    
    5.compiler依赖的buid.gradle文件内容如下:
    apply plugin: 'java-library'
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
    
        // 用于生成Java文件的库
        implementation 'com.squareup:javapoet:1.7.0'
        implementation 'com.google.auto.service:auto-service:1.0-rc2'
    }
    
    //jdk版本
    sourceCompatibility = "1.7"
    targetCompatibility = "1.7"
    
    

    效果

    完成上面的代码编写之后,点击make project就能看到生成的java文件:


    image.png image.png

    备注

    通过以上的步骤就已经可以通过AbstractProcessor一个空的类和一个带一个方法的java类了,以后还有许多知识需要学习!
    我在调试这个程序的时候发现log总是看不到,之后发现是看的位置不对,网上很多帖子都是讲的是怎么用旧版本的studio查看log,但是我用的是最新的3.5.2的版本,后面通过摸索还是看到log了,下面通过截图把详细的信息也展示出来:

    image.png
    最后附上源码地址:https://github.com/stormdzh/AbstractProcessorDemo
    欢迎大家一起学习研究!

    相关文章

      网友评论

          本文标题:Android使用AbstractProcessor生成类和方法

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