怎么做可以直播的网站,WordPress多用户商城插件,WordPress免费自动采集,电子商务网站建设模板面试官: ButterKnife为什么执行效率为什么比其他注入框架高#xff1f;它的原理是什么心理分析#xff1a; ButterKnife框架一直都是使用#xff0c;很少又开发者对butterknife深入研究的#xff0c;既然你是面试Android高级岗位#xff0c;自然需要有相应被问到原理的准备…面试官: ButterKnife为什么执行效率为什么比其他注入框架高它的原理是什么心理分析 ButterKnife框架一直都是使用很少又开发者对butterknife深入研究的既然你是面试Android高级岗位自然需要有相应被问到原理的准备面试官想问你对注解处理器了解多少Android编译流程有多少认识**求职者:**应该从 注解处理器原理 与优势说起肯定注解处理器对解放生产力的作用。然后可以引申常见的 ButterknifeDagger2DBFlow。这才是加分项优势我们平常在使用Java进行开发Android时经常会需要写很多重复冗余的样板代码开发中最常见的一种就是findViewById了如果一个界面有很多View写起来那叫一个要死要死。于是我们注解处理器可以帮助解决冗余的代码的由于是在编译器进行生成的代码并不是通过反射实现所以性能优势是非常高的加快开发速度由于减少了写繁琐的代码会对项目进度起有利的作用接下来我们一起来看注解处理的原理在android开发中比较常用到的第三方库中有不少用到了 注解处理器(Annotation Processor)。 比较常见的就有 ButterknifeDagger2DBFlow 等。注解Java中存在不少关于注解的Api, 比如Override用于覆盖父类方法Deprecated表示已舍弃的类或方法属性等android中又多了一些注解的扩展如NonNull, StringRes, IntRes等。代码自动生成使用代码自动生成一是为了提高编码的效率二是避免在运行期大量使用反射通过在编译期利用反射生成辅助类和方法以供运行时使用。注解处理器的处理步骤主要有以下在java编译器中构建编译器开始执行未执行过的注解处理器循环处理注解元素(Element)找到被该注解所修饰的类方法或者属性生成对应的类并写入文件判断是否所有的注解处理器都已执行完毕如果没有继续下一个注解处理器的执行(回到步骤1)Butterknife注解处理器的例子Butterknife的注解处理器的工作方式如下定义一个非私有的属性变量添加该属性变量的注解和传入id调用Butterknife.bind(..)方法。当你点击Android Studio的Build按钮时Butterknife先是按照上述步骤生成了对应的辅助类和方法。在代码执行到bind(..)方法时Butterknife就去调用之前生成的辅助类方法完成对被注解元素的赋值操作。自定义注解处理器了解了基本的知识点后我们应该尝试去使用这些技巧。 接下来是实践时间我们来开发一个简单的例子利用注解处理器来自动产生随机数字和随机字符串。首先创建一个project。创建lib_annotations 这是一个纯java的module不包含任何android代码只用于存放注解。创建lib_compiler 这同样是一个纯java的module。该module依赖于步骤2创建的module_annotation,处理注解的代码都在这里该moduule最终不会被打包进apk所以你可以在这里导入任何你想要的任意大小依赖库。创建lib_api, 对该module不做要求可以是android library或者java library或者其他的。该module用于调用步骤3生成的辅助类方法。1. 添加注解在lib_annotations中添加两个注解RandomString, RandomInt分别用于生成随机数字和随机字符串:Retention(CLASS)Target(value FIELD)public interface RandomString {}复制代码Retention(CLASS)Target(value FIELD)public interface RandomInt { int minValue() default 0; int maxValue() default 65535;}复制代码interface 自定义注解使用 interface 作为类名修饰符Target 该注解所能修饰的元素类型可选类型如下public enum ElementType { TYPE, //类 FIELD, //属性 METHOD, //方法 PARAMETER, //参数 CONSTRUCTOR, //构造函数 LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER, TYPE_USE; private ElementType() { }}复制代码Retention 该注解的保留策略有三种选项public enum RetentionPolicy { SOURCE, //被编译器所忽略 CLASS, //被编译器保留至类文件但不会保留至运行时 RUNTIME //保留至类文件且保留至运行时能在运行时反射该注解修饰的对象}复制代码2. 注解处理器真正处理注解并生成代码的操作都在这里。 在写代码之前我们需要先导入两个重要的库以及我们的注解模块compile com.google.auto.service:auto-service:1.0-rc4compile com.squareup:javapoet:1.9.0implementation project(:lib_annotations)复制代码新建类RandomProcessor.java:AutoService(Processor.class)public class RandomProcessor extends AbstractProcessor{ Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); } Override public SourceVersion getSupportedSourceVersion() { return super.getSupportedSourceVersion(); } Override public Set getSupportedAnnotationTypes() { return super.getSupportedAnnotationTypes(); } Override public boolean process(Set extends TypeElement set, RoundEnvironment roundEnvironment) { return false; }}复制代码AutoService AutoService(Processor.class)会告诉编译器该注解处理器的存在并在编译时自动在META-INF/services下生成javax.annotation.processing.Processor文件文件的内容为com.rhythm7.lib_compiler.RandomProcessor复制代码也就是说你所声明的注解处理器都会在被写入这个配置文件中。 这样子当外部程序装载这个模块的时候就能通过该模块的jar包下的META-INF/services下找到具体的注解处理器的实现类名并加载实例化完成模块的注入。 注解处理器需要实现AbstractProcessor接口并实现对应的方法init() 可选 在该方法中可以获取到processingEnvironment对象借由该对象可以获取到生成代码的文件对象, debug输出对象以及一些相关工具类getSupportedSourceVersion() 返回所支持的java版本一般返回当前所支持的最新java版本即可getSupportedAnnotationTypes() 你所需要处理的所有注解该方法的返回值会被process()方法所接收process() 必须实现 扫描所有被注解的元素并作处理最后生成文件。该方法的返回值为boolean类型若返回true,则代表本次处理的注解已经都被处理不希望下一个注解处理器继续处理否则下一个注解处理器会继续处理。初始化较详细代码如下:private static final List 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();}Overridepublic SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported();}Overridepublic Set getSupportedAnnotationTypes() { Set annotations new LinkedHashSet(); for (Class extends Annotation annotation : RANDOM_TYPES) { annotations.add(annotation.getCanonicalName()); } return annotations;}复制代码处理注解在process()方法中执行以下操作扫描所有注解元素并对注解元素的类型做判断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 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 %2$s