Android APT开发教程 四 apt生成代码与所注释元素之间的交互

github项目代码地址

https://github.com/979451341/TestAPT


怎么配置环境上篇文章说了
http://blog.csdn.net/z979451341/article/details/79126413

我准备写一个apt通过注解给int类型的变量赋值

在annotation中,创建两个注解,为何要有两个呢,第一个是为了获取整个activity的信息,第二个是为了标注需要处理的元素。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface TestActivity {
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestInt {
    int value() default  0;
}
我们第一个注释用在类名上面为了获取整个类里面所有的元素,但是可能注释了多个类,roundEnv.getElementsAnnotatedWith返回的是多个类的集合,然后顺序取出类,通过工具类elementUtils.getAllMembers获取类里所有的元素,然后判断是否有注释,如果有做相应处理。

 @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(TestActivity.class);
        for (Element element : elements) {
            // 判断是否Class
            TypeElement typeElement = (TypeElement) element;
            List<? extends Element> members = elementUtils.getAllMembers(typeElement);

            for (Element item : members) {
                TestInt diView = item.getAnnotation(TestInt.class);
                if (diView == null){
                    continue;
                }

            }

        return true;
    }

接下来说一下如何处理,在取出类A的时候,创建类继承类A并根据类A的名字来取类名,并创建一个函数来获取这个类A的实例,后面在从类A一个一个取出元素的时候判断是否有注解,如果有就在之前的函数里添加一行代码,对类A的元素进行赋值。

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(TestActivity.class);
        for (Element element : elements) {
            // 判断是否Class
            TypeElement typeElement = (TypeElement) element;
            List<? extends Element> members = elementUtils.getAllMembers(typeElement);
            MethodSpec.Builder bindViewMethodSpecBuilder = MethodSpec.methodBuilder("setDefualt")
                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                    .returns(TypeName.VOID)
                    .addParameter(ClassName.get(typeElement.asType()), "activity");

            for (Element item : members) {
                TestInt diView = item.getAnnotation(TestInt.class);
                if (diView == null){
                    continue;
                }
                bindViewMethodSpecBuilder.addStatement(String.format("activity.%s = %s",item.getSimpleName(),diView.value()));
            }
            TypeSpec typeSpec = TypeSpec.classBuilder("Test" + element.getSimpleName())
                    .superclass(TypeName.get(typeElement.asType()))
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                    .addMethod(bindViewMethodSpecBuilder.build())
                    .build();
            JavaFile javaFile = JavaFile.builder(getPackageName(typeElement), typeSpec).build();
            try {
                javaFile.writeTo(processingEnv.getFiler());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

完整注解处理器代码如下

@AutoService(Processor.class)
public class TestProcessor extends AbstractProcessor {
    private Elements elementUtils;
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        // 规定需要处理的注解
        return Collections.singleton(TestActivity.class.getCanonicalName());
    }
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(TestActivity.class);
        for (Element element : elements) {
            // 判断是否Class
            TypeElement typeElement = (TypeElement) element;
            List<? extends Element> members = elementUtils.getAllMembers(typeElement);
            MethodSpec.Builder bindViewMethodSpecBuilder = MethodSpec.methodBuilder("setDefualt")
                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                    .returns(TypeName.VOID)
                    .addParameter(ClassName.get(typeElement.asType()), "activity");

            for (Element item : members) {
                TestInt diView = item.getAnnotation(TestInt.class);
                if (diView == null){
                    continue;
                }
                bindViewMethodSpecBuilder.addStatement(String.format("activity.%s = %s",item.getSimpleName(),diView.value()));
            }
            TypeSpec typeSpec = TypeSpec.classBuilder("Test" + element.getSimpleName())
                    .superclass(TypeName.get(typeElement.asType()))
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                    .addMethod(bindViewMethodSpecBuilder.build())
                    .build();
            JavaFile javaFile = JavaFile.builder(getPackageName(typeElement), typeSpec).build();
            try {
                javaFile.writeTo(processingEnv.getFiler());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }
    private String getPackageName(TypeElement type) {
        return elementUtils.getPackageOf(type).getQualifiedName().toString();
    }
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        elementUtils = processingEnv.getElementUtils();
    }
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.RELEASE_7;
    }
}



使用注解,注意@TestInt(value = 1)和@TestInt(1)效果一样

@TestActivity
public class MainActivity extends Activity {

    @TestInt
    int a;
    @TestInt(value = 1)
    int b;
    @TestInt(1)
    int c;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TestMainActivity.setDefualt(this);
        Log.v("zzw"," a:"+a+" b:"+b+" c:"+c);
    }


}
生成代码如下,生成代码在:app/build/generated/source/apt/下
public final class TestMainActivity extends MainActivity {
  public static void setDefualt(MainActivity activity) {
    activity.a = 0;
    activity.b = 1;
    activity.c = 1;
  }
}

效果
01-22 15:24:48.712 5647-5647/com.example.zth.myapplication V/zzw:  a:0 b:1 c:1


总结
我们使用在类名的注解是为了获取整个类的信息,使用在变量的注解是为了分清哪个元素需要处理,生成的代码则是为了完成实际的业务





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值