您的位置:首页 > 移动开发 > Android开发

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

2018-01-30 19:42 513 查看
github项目代码地址

https://github.com/979451341/TestAPT

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

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

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

@Target(ElementType.TYPE)[url=mailto:br/>@Retention(RetentionPolicy.CLASS)
@Retention(RetentionPolicy.CLASS)
}

@Target(ElementType.FIELD)[url=mailto:br/>@Retention(RetentionPolicy.RUNTIME)
@Retention(RetentionPolicy.RUNTIME)
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;[url=mailto:br/>@Override
@Override
// 规定需要处理的注解
return Collections.singleton(TestActivity.class.getCanonicalName());[url=mailto:br/>}
@Override
}
@Override
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


总结
我们使用在类名的注解是为了获取整个类的信息,使用在变量的注解是为了分清哪个元素需要处理,生成的代码则是为了完成实际的业务
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  APT