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;
}
}