Android APT开发教程 五 使用注释完成findViewById和setContentView

github项目代码地址

https://github.com/979451341/TestAPT

之前我们做了一个能够给int赋值的apt,这个时候我想到好像控件类似TextView的id值也是int类型,所以我也可以给控件id赋值



不过有一个问题就是如何去分辨哪个是int类型,哪个是控件的id
但是我们可以去试一下获取这两种元素的信息有何不同

比如我这样一弄,就可以打印出类似Element类似分类的属性
   @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);
            TestActivity activity = typeElement.getAnnotation(TestActivity.class);
            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("%s  %s",item.getKind(),item.asType().getKind()));
            }
            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;
    }

结果如下

public final class TestMainActivity extends MainActivity {
  public static void setDefualt(MainActivity activity) {

    FIELD  INT;
    FIELD  INT;
    FIELD  INT;
    FIELD  DECLARED;
  }
}
可以看到item.asType().getKind()能够分辨控件id和int类型的区别,
我把加代码的那段换成如下,就是判断如果类型为INT就正常int赋值,如果类型为DECLARED就findViewById
                if(item.asType().getKind() == INT)
                bindViewMethodSpecBuilder.addStatement(String.format("activity.%s = %s",item.getSimpleName(),diView.value()));
                 if(item.asType().getKind() == DECLARED)
                bindViewMethodSpecBuilder.addStatement(String.format("activity.%s = (%s)activity.findViewById(%s)",item.getSimpleName(),item.asType().toString(),diView.value()));
后来通过实验,代码运行正常,

@TestActivity
public class MainActivity extends Activity {

    @TestInt
    int a;
    @TestInt(value = 1)
    int b;
    @TestInt(1)
    int c;
    @TestInt(R.id.tv1)
    TextView tv1;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TestMainActivity.setDefualt(this);
        setContentView(R.layout.activity_main);


        Log.v("zzw"," a:"+a+" b:"+b+" c:"+c);
        tv1.setText(" a:"+a+" b:"+b+" c:"+c);
    }


}
但是我还记得R.layout.activity_main也是int类型,我们应该能够使用注解来设置布局,这注解用在哪呢,我就用在TestActivity这个注解吧

那我就要改变TestActivity的代码,加个int的变量

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface TestActivity {
    int value() default  0;
}
然后在注解处理器里添加一行接收TestActivity的value值并给Activity设置布局的代码

            TestActivity activity = typeElement.getAnnotation(TestActivity.class);

            if(activity == null){
                continue;
            }
            bindViewMethodSpecBuilder.addStatement(String.format("activity.setContentView(%s)",activity.value()));

使用如下:

@TestActivity(R.layout.activity_main)
public class MainActivity extends Activity {

    @TestInt
    int a;
    @TestInt(value = 1)
    int b;
    @TestInt(1)
    int c;
    @TestInt(R.id.tv1)
    TextView tv1;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TestMainActivity.setDefualt(this);


        Log.v("zzw"," a:"+a+" b:"+b+" c:"+c);
        tv1.setText(" a:"+a+" b:"+b+" c:"+c);
    }


}

完整的注释处理器代码如下
@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);
            TestActivity activity = typeElement.getAnnotation(TestActivity.class);
            MethodSpec.Builder bindViewMethodSpecBuilder = MethodSpec.methodBuilder("setDefualt")
                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                    .returns(TypeName.VOID)
                    .addParameter(ClassName.get(typeElement.asType()), "activity");

            if(activity == null){
                continue;
            }
            bindViewMethodSpecBuilder.addStatement(String.format("activity.setContentView(%s)",activity.value()));
            for (Element item : members) {
                TestInt diView = item.getAnnotation(TestInt.class);

                if (diView == null){
                    continue;
                }



                if(item.asType().getKind() == INT)
                bindViewMethodSpecBuilder.addStatement(String.format("activity.%s = %s",item.getSimpleName(),diView.value()));
                 if(item.asType().getKind() == DECLARED)
                bindViewMethodSpecBuilder.addStatement(String.format("activity.%s = (%s)activity.findViewById(%s)",item.getSimpleName(),item.asType().toString(),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;
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值