2.Android注解-编译时生成代码 APT(Annotation Processing Tool ) 实例说明
来源:互联网 发布:登录淘宝要脸部拍摄 编辑:程序博客网 时间:2024/05/29 15:50
项目构建如下
建一个主工程,一个纯注解的anotation java工程,一个编译生成代码的compiler java工程,一个android library库。
compiler java工程不会打包入项目的,只是在编译的时候生成相关代码而已。
|—-
—app(主android项目)
—rulangtool-api(android library)
—rualngtool-annotation(java library)
—rulangtool-commpiler(java library)
工程如上(图片无法上传了,蛋疼啊 只能如此写结构图)
在app工程里面引入的是
compile project(':rulangtool-annotation') compile project(':rulangtool-api') // apt project(':rulangtool-compiler') // 刚开始我写的apt,后修改配置位annotationProcessor annotationProcessor project(':rulangtool-compiler')
rulangtool-compiler只是用在编译时期生成代码,其他时间并无其他作用的。
rulangtool-annotation 是一个注解java library。
拿我们常用的android butterknife来做说明。举例BindView,Onclick(View)2个注解来说明。
rulangtool-annotation里的代码如下:
注解部分文章
@Retention(RetentionPolicy.CLASS)@Target(ElementType.FIELD)public @interface BindView { int value();}@Retention(RetentionPolicy.CLASS)@Target(ElementType.METHOD)public @interface OnClick { int[] value();}
rulangtool-commpiler来说明一下。
工程引入
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile project(':rulangtool-annotation') compile 'com.squareup:javapoet:1.7.0' compile 'com.google.auto.service:auto-service:1.0-rc2'}
javax.lang.model.element 用于 Java 编程语言的模型元素的接口。
AnnotationMirror表示一个注释。AnnotationValue 表示注释类型元素的值。AnnotationValueVisitor<R,P>注释类型元素值的 visitor,使用 visitor 设计模式的变体。Element 表示一个程序元素,比如包、类或者方法。ElementVisitor<R,P> 程序元素的 visitor,使用 visitor 设计模式的样式。ExecutableElement 表示某个类或接口的方法、构造方法或初始化程序(静态或实例),包括注释类型元素。Name 字符的不可变序列。PackageElement 表示一个包程序元素。TypeElement 表示一个类或接口程序元素。TypeParameterElement 表示一般类、接口、方法或构造方法元素的形式类型参数。VariableElement 表示一个字段、enum 常量、方法或构造方法参数、局部变量或异常参数。
BindViewFieldpublic class BindViewField { private VariableElement mVariableElement; private int mresId; public BindViewField(Element element) throws IllegalArgumentException{ if (element.getKind() != ElementKind.FIELD) { throw new IllegalArgumentException(String.format("Only fields can be annotated with @%s", BindView.class.getSimpleName())); } mVariableElement = (VariableElement) element; BindView bindView = mVariableElement.getAnnotation(BindView.class); mresId = bindView.value(); if (mresId < 0) { throw new IllegalArgumentException( String.format("value() in %s for field %s is not valid !", BindView.class.getSimpleName(), mVariableElement.getSimpleName())); } } /** * 获取变量名称 * @return */ public Name getFieldName() { return mVariableElement.getSimpleName(); } /** * 获取变量id * @return */ public int getResId() { return mresId; } /** * 获取变量类型 * @return */ public TypeMirror getFieldType() { return mVariableElement.asType(); }}
OnClickMethodpublic class OnClickMethod { private ExecutableElement mExecutableElement; private int[] resIds; private Name mMethodName; public OnClickMethod(Element element) throws IllegalArgumentException { if (element.getKind() != ElementKind.METHOD) { throw new IllegalArgumentException( String.format("Only methods can be annotated with @%s", OnClick.class.getSimpleName())); } mExecutableElement = (ExecutableElement) element; resIds = mExecutableElement.getAnnotation(OnClick.class).value(); if (resIds == null) { throw new IllegalArgumentException(String.format("Must set valid ids for @%s", OnClick.class.getSimpleName())); } else { for (int id : resIds) { if (id < 0) { throw new IllegalArgumentException(String.format("Must set valid id for @%s", OnClick.class.getSimpleName())); } } } mMethodName = mExecutableElement.getSimpleName(); List<? extends VariableElement> parameters = mExecutableElement.getParameters(); if (parameters.size() > 0) { throw new IllegalArgumentException( String.format("The method annotated with @%s must have no parameters", OnClick.class.getSimpleName())); } } /** * 获取方法名称 * @return */ public Name getMethodName() { return mMethodName; } /** * 获取id数组 * @return */ public int[] getResIds() { return resIds; }}
同一个类里面的注解处理
AnnotatedClasspublic class AnnotatedClass { private TypeElement mTypeElement; private ArrayList<BindViewField> mFields; private ArrayList<OnClickMethod> mMethods; private Elements mElements; public AnnotatedClass(TypeElement typeElement, Elements elements) { mTypeElement = typeElement; mElements = elements; mFields = new ArrayList<>(); mMethods = new ArrayList<>(); } public String getFullClassName() { return mTypeElement.getQualifiedName().toString(); } public void addField(BindViewField field) { mFields.add(field); } public void addMethod(OnClickMethod method) { mMethods.add(method); } public JavaFile generateFile() { //generateMethod MethodSpec.Builder injectMethod = MethodSpec.methodBuilder("inject") .addModifiers(Modifier.PUBLIC) .addAnnotation(Override.class) .addParameter(TypeName.get(mTypeElement.asType()), "host", Modifier.FINAL) .addParameter(TypeName.OBJECT, "source") .addParameter(TypeUtil.PROVIDER,"provider"); for(BindViewField field : mFields){ // find views injectMethod.addStatement("host.$N = ($T)(provider.findView(source, $L))", field.getFieldName(), ClassName.get(field.getFieldType()), field.getResId()); } for(OnClickMethod method :mMethods){ TypeSpec listener = TypeSpec.anonymousClassBuilder("") .addSuperinterface(TypeUtil.ANDROID_ON_CLICK_LISTENER) .addMethod(MethodSpec.methodBuilder("onClick") .addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC) .returns(TypeName.VOID) .addParameter(TypeUtil.ANDROID_VIEW, "view") .addStatement("host.$N()", method.getMethodName()) .build()) .build(); injectMethod.addStatement("View.OnClickListener listener = $L ", listener); for (int id : method.getResIds()) { // set listeners injectMethod.addStatement("provider.findView(source, $L).setOnClickListener(listener)", id); } } //generaClass TypeSpec injectClass = TypeSpec.classBuilder(mTypeElement.getSimpleName() + "$$RuLang") .addModifiers(Modifier.PUBLIC) .addSuperinterface(ParameterizedTypeName.get(TypeUtil.INJET, TypeName.get(mTypeElement.asType()))) .addMethod(injectMethod.build()) .build(); String packgeName = mElements.getPackageOf(mTypeElement).getQualifiedName().toString(); return JavaFile.builder(packgeName, injectClass).build(); }}
真正的编译器生成代码咋这个里面:
@AutoService(Processor.class)public class ViewInjectProcesser extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement>annotations, RoundEnvironment roundEnv) { }}
这句代码非常重要 TypeSpec injectClass = TypeSpec.classBuilder(mTypeElement.getSimpleName() + “
在rulangtool-api里面开始
private static void inject(Object host, Object object, Provider provider) { String className = host.getClass().getName(); try { Inject inject = injectMap.get(className); if (inject == null) { //利用反射实例话生成的对象,通过注入实例化相关字段或者关联方法。 Class<?> aClass = Class.forName(className + "$$RuLang"); inject = (Inject) aClass.newInstance(); injectMap.put(className, inject); } inject.inject(host, object, provider); } catch (Exception e) { e.printStackTrace(); } }
阅读全文
0 0
- 2.Android注解-编译时生成代码 APT(Annotation Processing Tool ) 实例说明
- 1.Android注解-编译时生成代码 APT(Annotation Processing Tool ) Poet 说明
- Android注解-编译时生成代码 (APT)
- android 使用apt(编译时注解) 自动生成第三方的狗皮膏药代码
- java annotation processing tools(APT)实例解析
- 【Annotation】Processing-Tool详解
- Android 编译时注解生成代码
- android apt编译时期自动生成代码
- java annotation processing 自动生成代码
- 利用APT实现Android编译时注解
- 利用APT实现Android编译时注解
- Android 利用 APT 技术在编译期生成代码
- Android 利用 APT 技术在编译期生成代码
- Android 利用 APT 技术在编译期生成代码
- Annotation注解APT(一):什么是Annotation注解
- Java编译时注解自动生成代码
- annotation processor tool(apt)的套路
- 使用dataBinding出现Warning:Using incompatible plugins for the annotation processing: android-apt.
- 服务器报的漏洞解决办法
- Android NDK编译静态链接库及动态链接库(librtmp编译小白填坑)
- 解决“Visual Studio 要求设计器使用文件中的第一个类。”方法
- 五子棋的Java实现 详解
- 设计模式——结构型模式
- 2.Android注解-编译时生成代码 APT(Annotation Processing Tool ) 实例说明
- 和为S的连续正数序列
- 基于SDK的支付接口服务端——支付宝,微信
- 小记(17831)
- RxJava2操作符之“Delay”
- SSM(六)跨域传输
- 借助扩展事件查看SQL 2016备份和还原操作的内幕
- 数模中常使用的Matlab绘图与Excel绘图
- 关于近期未更新通知