Java注解 编译_Java注解之编译时注解

新建两个module

annotation用来定义注解

compiler用来编写处理注解的代码

这两个module都要选择Java Library

b7ae85c1a8c04e2f11b7caf885363e63.png

那为什么要拆分两个module呢,因为编译期注解的处理代码是只在代码编译的时候使用的,所以这些代码要和主module分开拆成compiler,但是compiler又依赖于注解,主module也要使用注解。所以就将注解的定义也拆分出来。这样做的好处是可以在compiler中引入任何库,而不用考虑 Android 关于方法数的限制。例如Guava。

定义注解 @Retention(RetentionPolicy.CLASS)

@Target(ElementType.FIELD)

public @interface BindViewCompiler {

int value() default -1;

}

@Retention(RetentionPolicy.CLASS)

@Target(ElementType.METHOD)

public @interface OnClickCompiler {

int value() default -1;

}

复制代码

定义注解处理器 public class BindViewProcessor extends AbstractProcessor {

@Override

public SourceVersion getSupportedSourceVersion() {

return SourceVersion.latestSupported();

}

@Override

public Set getSupportedAnnotationTypes() {

Set types = new LinkedHashSet<>();

types.add(BindViewCompiler.class.getCanonicalName());

types.add(OnClickCompiler.class.getCanonicalName());

return types;

}

@Override

public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {

return false;

}

}

复制代码

定义一个描述Java文件的类ClassModel public class ClassModel {

/**

* 成员变量

*/

private HashSet variableElements;

/**

* 类方法

*/

private HashSet executableElements;

/**

* 包

*/

private PackageElement packageElement;

/**

* 类

*/

private TypeElement classElement;

public ClassModel(TypeElement classElement) {

this.classElement = classElement;

packageElement = (PackageElement) classElement.getEnclosingElement();

variableElements = new HashSet<>();

executableElements = new HashSet<>();

}

public void addVariableElement(VariableElement element) {

variableElements.add(element);

}

public void addExecutableElement(ExecutableElement element) {

executableElements.add(element);

}

/**

* 生成Java文件

*/

public void generateJavaFile(Filer filer) {

}

}

复制代码

实现process方法 private HashMap classMap;

@Override

public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {

// 因为扫描会有多轮,所以需要清空一下,classMap在init方法中初始化

classMap.clear();

for (Element element : roundEnvironment.getElementsAnnotatedWith(BindViewCompiler.class)) {

ClassModel model = checkModel(element);

model.addVariableElement((VariableElement) element);

}

for (Element element : roundEnvironment.getElementsAnnotatedWith(OnClickCompiler.class)) {

ClassModel model = checkModel(element);

model.addExecutableElement((ExecutableElement) element);

}

for (ClassModel model : classMap.values()) {

model.generateJavaFile(processingEnv.getFiler());

}

return true;

}

private ClassModel checkModel(Element element) {

// 获取当前类

TypeElement classElement = (TypeElement) element.getEnclosingElement();

String qualifiedName = classElement.getQualifiedName().toString();

// 查看是否已经保存在classMap中了,如果没有就新创建一个

ClassModel model = classMap.get(qualifiedName);

if (model == null) {

model = new ClassModel(classElement);

classMap.put(qualifiedName, model);

}

return model;

}

复制代码

实现generateJavaFile方法 /**

* 生成Java文件

*/

public void generateJavaFile(Filer filer) {

try {

JavaFileObject jfo = filer.createSourceFile(classElement.getQualifiedName() + "$$view_binding");

BufferedWriter bw = new BufferedWriter(jfo.openWriter());

bw.append("package ").append(packageElement.getQualifiedName()).append(";\n");

bw.newLine();

bw.append(getImportString());

bw.newLine();

bw.append("public class ").append(classElement.getSimpleName()).append("$$view_binding implements Injectable {\n");

bw.newLine();

bw.append(getFiledString());

bw.newLine();

bw.append(getConstructString());

bw.newLine();

bw.append("}");

bw.flush();

bw.close();

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 生成import代码

*/

private String getImportString() {

StringBuilder stringBuilder = new StringBuilder();

stringBuilder.append("import android.view.View;\n");

stringBuilder.append("import com.example.hao.learnself.date_2018_12_28.Injectable;\n");

stringBuilder.append("import ").append(classElement.getQualifiedName()).append(";\n");

HashSet importStrs = new HashSet<>();

for (VariableElement element : variableElements) {

importStrs.add("import " + element.asType().toString() + ";\n");

}

for (String str : importStrs) {

stringBuilder.append(str);

}

return stringBuilder.toString();

}

/**

* 生成成员变量

*/

private String getFiledString() {

return "private " + classElement.getSimpleName().toString() + " target;\n";

}

/**

* 生成构造函数

*/

private String getConstructString() {

StringBuilder stringBuilder = new StringBuilder();

stringBuilder.append("public ").append(classElement.getSimpleName().toString()).append("$$view_binding")

.append("(").append(classElement.getSimpleName()).append(" target, ").append("View view) {\n");

stringBuilder.append("this.target = target;\n");

for (VariableElement element : variableElements) {

int resId = element.getAnnotation(BindViewCompiler.class).value();

stringBuilder.append("target.").append(element.getSimpleName()).append(" = (").append(element.asType().toString())

.append(")view.findViewById(").append(resId).append(");\n");

}

for (ExecutableElement element : executableElements) {

int resId = element.getAnnotation(OnClickCompiler.class).value();

stringBuilder.append("view.findViewById(").append(resId).append(").setOnClickListener(new View.OnClickListener() {\n")

.append("@Override\n").append("public void onClick(View v) {\n")

.append("target.").append(element.getSimpleName()).append("();\n")

.append("}\n});\n");

}

stringBuilder.append("}");

return stringBuilder.toString();

}

复制代码

注册Processor。 Processor需要注册一下才能被注解处理器处理,在src/main/resources/META-INF/services下创建一个javax.annotation.processing.Processor文件,如果没有当前目录就新建一个

4a3e927e45f3c7d8313f1fc537ab5c40.png

在该文件中写入Processor的全类名 com.example.compiler.BindViewProcessor

复制代码

build一下并查看生成的文件,在/app/build/generated/source/apt下 package com.example.hao.learnself.date_2018_12_28;

import android.view.View;

import com.example.hao.learnself.date_2018_12_28.Injectable;

import com.example.hao.learnself.date_2018_12_28.AnnotationTestActivity;

import android.widget.TextView;

public class AnnotationTestActivity$$view_binding implements Injectable {

private AnnotationTestActivity target;

public AnnotationTestActivity$$view_binding(AnnotationTestActivity target, View view) {

this.target = target;

target.compileSumTv = (android.widget.TextView)view.findViewById(2131165231);

target.compileAddBtn = (android.widget.TextView)view.findViewById(2131165230);

view.findViewById(2131165230).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

target.compileAdd();

}

});

}

}

复制代码

定义Injectable接口和Injection工具类 public interface Injectable {

}

public class Injection {

private static final String SUFFIX = "$$view_binding";

public static void inject(@NonNull Activity target) {

inject(target, target.getWindow().getDecorView());

}

public static void inject(@NonNull Object target, @NonNull View view) {

String className = target.getClass().getName();

try {

// 通过反射创建

Class> clazz = target.getClass().getClassLoader().loadClass(className + SUFFIX);

Constructor constructor = (Constructor) clazz.getConstructor(target.getClass(), View.class);

constructor.newInstance(target, view);

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

}

复制代码

在测试页面中使用 public class AnnotationTestActivity extends BaseActivity {

@BindViewRuntime(R.id.runtime_add_btn)

private TextView runtimeAddBtn;

@BindViewRuntime(R.id.runtime_sum_tv)

private TextView runtimeSumTv;

@BindViewCompiler(R.id.compile_add_btn)

TextView compileAddBtn;

@BindViewCompiler(R.id.compile_sum_tv)

TextView compileSumTv;

@Override

protected int getLayoutId() {

return R.layout.activity_annotation_test;

}

@Override

protected void initView() {

Injection.inject(this);

}

@OnClickRuntime(R.id.runtime_add_btn)

void runTimeAdd() {

String text = runtimeSumTv.getText().toString();

runtimeSumTv.setText(String.valueOf(Integer.parseInt(text) + 1));

}

@OnClickCompiler(R.id.compile_add_btn)

void compileAdd() {

String text = compileSumTv.getText().toString();

compileSumTv.setText(String.valueOf(Integer.parseInt(text) + 1));

}

}

复制代码

查看效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值