ButterKnife为什么执行效率为什么比其他注入框架高?它的原理是什么

较详细代码如下:

private static final List<Class<? extends Annotation>> RANDOM_TYPES

= Arrays.asList(RandomInt.class, RandomString.class);

private Messager messager;

private Types typesUtil;

private Elements elementsUtil;

private Filer filer;

private TypeonProcess()per.init(processingEnv);

messager = processingEnv.getMessager();

typesUtil = processingEnv.getTypeUtils();

elementsUtil = processingEnv.getElementUtils();

filer = processingEnv.getFiler();

}

@Override

public SourceVersion getSupportedSourceVersion() {

return SourceVersion.latestSupported();

}

@Override

public Set getSupportedAnnotationTypes() {

Set annotations = new LinkedHashSet<>();

for (Class<? extends Annotation> annotation : RANDOM_TYPES) {

annotations.add(annotation.getCanonicalName());

}

return annotations;

}

处理注解

process()方法中执行以下操作:

1.扫描所有注解元素,并对注解元素的类型做判断

for (Element element : roundEnv.getElementsAnnotatedWith(RandomInt.class)) {

//AnnotatedRandomInt是对被RandomInt注解的Elment的简单封装

AnnotatedRandomInt randomElement = new AnnotatedRandomInt(element);

messager.printMessage(Diagnostic.Kind.NOTE, randomElement.toString());

//判断被注解的类型是否符合要求

if (!element.asType().getKind().equals(TypeKind.INT)) {

messager.printMessage(Diagnostic.Kind.ERROR, randomElement.getSimpleClassName().toString() + “#”

  • randomElement.getElementName().toString() + " is not in valid type int");

}

//按被注解元素所在类的完整类名为key将被注解元素存储进Map中,后面会根据key生成类文件

String qualifier = randomElement.getQualifiedClassName().toString();

if (annotatedElementMap.get(qualifier) == null) {

annotatedElementMap.put(qualifier, new ArrayList());

}

annotatedElementMap.get(qualifier).add(randomElement);

}

生成类文件

将之前以注解所在类为key的map遍历,并以key值为分组生成类文件。

for (Map.Entry<String, List> entry : annotatedElementMap.entrySet()) {

MethodSpec constructor = createConstructor(entry.getValue());

TypeSpec binder = createClass(getClassName(entry.getKey()), constructor);

JavaFile javaFile = JavaFile.builder(getPackage(entry.getKey()), binder).build();

javaFile.writeTo(filer);

}

生成类、构造函数、代码段以及文件都是利用到了javapoet依赖库。当然你也可以选择拼接字符串和自己用文件IO写入,但是用javapoet要更方便得多。

private MethodSpec createConstructor(List randomElements) {

AnnotatedRandomElement firstElement = randomElements.get(0);

MethodSpec.Builder builder = MethodSpec.constructorBuilder()

.addModifiers(Modifier.PUBLIC)

.addParameter(TypeName.get(firstElement.getElement().getEnclosingElement().asType()), “target”);

for (int i = 0; i < randomElements.size(); i++) {

addStatement(builder, randomElements.get(i));

}

return builder.build();

}

private void addStatement(MethodSpec.Builder builder, AnnotatedRandomElement randomElement) {

builder.addStatement(String.format(

“target.%1 s = s = %2 s=s”,

randomElement.getElementName().toString(),

randomElement.getRandomValue())

);

}

private TypeSpec createClass(String className, MethodSpec constructor) {

return TypeSpec.classBuilder(className + “_Random”)

.addModifiers(Modifier.PUBLIC, Modifier.FINAL)

.addMethod(constructor)

.build();

}

private String getPackage(String qualifier) {

return qualifier.substring(0, qualifier.lastIndexOf(“.”));

}

private String getClassName(String qualifier) {

return qualifier.substring(qualifier.lastIndexOf(“.”) + 1);

}

通过以上几行代码,创建了类文件。在类的构造函数中添加参数(target), 并为每一个被注解元素添加语句"target.%1$s = %2$s",最后通过javaFile.writeTo(filer)完成文件写入。

3. 调用生成类的方法

在lib_api中新建一个类:RandomUtil.java,添加注入方法:

public static void inject(Object object) {

Class bindingClass = Class.forName(object.getClass().getCanonicalName() + “_Random”);

Constructor constructor = bindingClass.getConstructor(object.getClass());

constructor.newInstance(object);

}

这里利用反射找到了以“Object类名_Random”命名的生成类,并调用它的构造方法。而在我们之前的注解处理器中,我们已在生成类的构造方法中实现了属性的赋值操作。

4. 使用生成类

在app module中依赖刚才创建的库:

implementation project(‘:lib_annotations’)

implementation project(‘:lib_api’)

annotationProcessor project(‘:lib_compiler’)

在Activity中的使用

public class MainActivity extends AppCompatActivity {

@RandomInt(minValue = 10, maxValue = 1000)

int mRandomInt;

@RandomString

String mRandomString;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

RandomUtil.inject(this);

Log.i("RandomInt ==> ", mRandomInt + “”);

Log.i("RandomString ==> ", mRandomString);

}

}

编译,运行,查看结果:

RandomInt ==>: 700

RandomString ==>: HhRayFyTtt

被注解的元素成功被自动赋值,说明注入成功。

注解处理的使用可参考完整的demo地址

调试

注解处理器的debug跟普通的代码debug有点不同:

在当前工程路径下输入命令

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值