美文网首页
玩转Android Annotation Processor

玩转Android Annotation Processor

作者: 编程小猪 | 来源:发表于2017-03-17 16:55 被阅读0次

    android-apt 与 AnnotationProcessor

    APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。(额外的处理包括,修改源文件,增加新代码,甚至添加新的Annotation)

    android-apt是一个gradle插件,始于三年前 ByHugo*Visser*

    AnnotationProcessor是Android Gradle 插件 2.2 版本提供的插件

    能干什么?

    少些代码(增加开发效率,代码看起来更优雅)

    解耦(ActivityRouter)

    谁都在用?

    EventBus、Retrofit、Dagger2、ButterKnife等等

    像官方靠齐,本文均采用AnnotationProcessor进行示范

    初体验:

    AnnotationProcessor 所需环境:

    gradle 插件2.2 +

    AndroidStudio 2.2 (AndroidStudio 2.3调试不成功,未知原因)

    所需知识:

    Java注解知识(https://joyrun.github.io/2016/07/18/java-annotation)JavaPoet(http://www.jianshu.com/p/95f12f72f69a)

    1、Gradle插件

    buildscript{repositories{        jcenter()    }dependencies{classpath'com.android.tools.build:gradle:2.2.1'}}

    2、新建Annotation定义的Module

    build.gradle定义如下:

    apply plugin:'java'dependencies{compilefileTree(dir:'libs',include: ['*.jar'])}sourceCompatibility="1.7"targetCompatibility="1.7"

    当然你也可以不新建一个Module来做,写在业务Module里,但是Compiler要依赖,所以不建议写在也业务里。

    3、新建注解处理Module

    build.gradle定义如下:

    applyplugin:'java'dependencies{compilefileTree(include: ['*.jar'],dir:'libs')compile'com.google.auto.service:auto-service:1.0-rc2'compile'com.squareup:javapoet:1.7.0'compileproject(':annotation')}sourceCompatibility="1.7"targetCompatibility="1.7"

    auto-service:可以将自定义的Compiler自动注册进去

    javapoet:优雅的生成Java类的工具

    compile project(':annotation') 依赖刚才新建的annotation module 因为需要引用annotation

    注解处理是整个Annotation Processor的核心,对Annotation进行处理的就是这个部分。

    继承Java提供的AbstractProcessor,重写相关方法就可以实现对Annotation的处理

    @AutoService(Processor.class)publicclassUrlCompilerextendsAbstractProcessor{privatestaticfinalStringPACKAGE="com.baidu.appsearch.config";privatestaticfinalStringCLASSNAME_SUFFIX="Injection";@OverridepublicSet getSupportedAnnotationTypes() {returnCollections.singleton(UrlClass.class.getCanonicalName());}@Overridepublic boolean process(Setannotations, RoundEnvironment roundEnv) {for(Elementelement : roundEnv.getElementsAnnotatedWith(UrlClass.class)) {TypeElement typeElement = (TypeElement) element;ListelementList = typeElement.getEnclosedElements();HashMap urls =newHashMap<>();for(Elemente : elementList) {Urlurl = e.getAnnotation(Url.class);if(url !=null) {if(!url.value().startsWith("/") && !url.value().startsWith("http")) {thrownewRuntimeException("url should start with / or http");}VariableElement variableElement = (VariableElement) e;urls.put(variableElement.getConstantValue().toString(), url.value());}}MethodSpec constructor = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC).build();StringBuilder sb =newStringBuilder();Iteratoriter = urls.entrySet().iterator();while(iter.hasNext()) {Map.Entry entry = (Map.Entry) iter.next();Objectkey = entry.getKey();Objectval = entry.getValue();sb.append("urls.put(\"").append(key).append("\"").append(",\"").append(val).append("\");");}intinitialCapacity = urls.size();MethodSpec init = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).returns(HashMap.class).addCode("HashMap urls = new HashMap("+ initialCapacity +");"+ sb.toString()).addCode("return urls;").build();StringclassNameStr = typeElement.getSimpleName().toString();ClassName className = ClassName.get(PACKAGE,CLASSNAME_SUFFIX);TypeSpec settingManager = TypeSpec.classBuilder(classNameStr +CLASSNAME_SUFFIX).addModifiers(Modifier.PUBLIC, Modifier.FINAL).addSuperinterface(className).addMethod(constructor).addMethod(init).build();Stringfull = typeElement.getQualifiedName().toString();StringpackageName = full.substring(0, full.indexOf(classNameStr)-1);JavaFile javaFile = JavaFile.builder(packageName, settingManager).build();try{javaFile.writeTo(processingEnv.getFiler());}catch(IOException e) {e.printStackTrace();}}returntrue;}@OverridepublicSourceVersion getSupportedSourceVersion() {returnSourceVersion.RELEASE_7;}@Overridepublic synchronizedvoidinit(ProcessingEnvironment processingEnv) {super.init(processingEnv);}}

    其中的process方法就是处理Annotation的核心方法,可以获取到Annotation,与反射的思路类似。

    4、运行

    运行之后会自动生成Processor处理后的java类

    怎么调试?

    如何调试process方法?这和一般App调试是不一样的,因为process方法是运行在编译期,所以需要配置远程调试。

    新建一个调试

    其他保持默认即可

    配置要调试的Task

    复制进去刚才remote的command参数,注意suspend改成y

    在process方法里加断点

    点击运行

    点击启动调试器,过会儿就会在断点停住了

    参考资料:

    1、http://www.jianshu.com/p/2494825183c5

    2、http://blog.csdn.net/tomatomas/article/details/53998585

    相关文章

      网友评论

          本文标题:玩转Android Annotation Processor

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