javapoet:大师参考链接:https://blog.csdn.net/IO_Field/article/details/89355941
总共3个module,之间的联系
创建java library:Lib_annontation
创建注解类:
@Target(ElementType.FIELD) //声明注解作用域(FIELD:成员变量,METHOD:方法...)
@Retention(RetentionPolicy.SOURCE) //注解处理的生命周期SOURCE:只在java文件有用,即编译class文件前,Class/RUNTIME
public @interface BindView {
int value();
}
创建java library:Lib_complier
配置Lib_complier的build.gradle:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.google.auto.service:auto-service:1.0-rc4'
implementation 'com.squareup:javapoet:1.11.1'
compile project(path: ':lib_annonation')//依赖注解类
}
Javepoet(poet:java诗人):动态生成代码,与反射相似。将类、方法、变量都为对象
1.创建注解处理器,一个基础
@AutoService(Processor.class)
public class MyProcess extends AbstractProcessor {
/**声明注解处理器的注解
*/
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new HashSet<>();
types.add(BindView.class.getCanonicalName());
return types;
}
/**声明注解处理器的源版本
*/
@Override
public SourceVersion getSupportedSourceVersion() {
return processingEnv.getSourceVersion();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(BindView.class);
// 接口:给注解处理器创建的类使用
ClassName interface_viewbinder = ClassName.get("com.zzn.test5555555", "ViewBind");
//key为Activity名,Value为成员遍历的集合
Map<String, List<VariableElement>> map = new HashMap<>();
getMap(map, elements);
Iterator<String> activitylist = map.keySet().iterator();
while (activitylist.hasNext()) {
//类名 BBBBActivity
String activityName = activitylist.next();
//成员变量List
List<VariableElement> fieldlist = map.get(activityName);
//拿到第一个成员变量的上一级Element 这一级: element.toString() = com.zzn.test5555555.MainActivity
Element enclosingElement = fieldlist.get(0).getEnclosingElement();
TypeElement classElement = (TypeElement) enclosingElement;//获取节点的具体类型:MainActivity,可以拿父类和接口
//方法参数设置:bind(MainActivity tager)
TypeMirror typeMirror = enclosingElement.asType();
TypeName typeName = TypeName.get(typeMirror);
ParameterSpec parameterSpec = ParameterSpec.builder(typeName, "tager").build();
//类的接口参数设置:implements ViewBind<MainActivity> :ViewBind接口不是类中的需要 ClassName.getClassName方式获取
//ParameterizedTypeName.get(ClassName,TypeName); 接口 / 泛型
ParameterizedTypeName interface_Parame = ParameterizedTypeName.get(interface_viewbinder, typeName);
//包名 获取2中方法
String packageName = processingEnv.getElementUtils().getPackageOf(enclosingElement).toString();
//String packageName = classElement.getEnclosingElement().toString();
//创建方法
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("bind")
.addModifiers(Modifier.PUBLIC)
.addParameter(parameterSpec)
.returns(void.class);
// 如:tager.button=(Button)tager.findViewById(2131165320);
for (VariableElement variableElement : fieldlist) {
//成员变量名字
//成员变量类型
//控件id
String name = variableElement.getSimpleName().toString();
TypeMirror typeMirror2 = variableElement.asType();
// FieldSpec fieldSpec=FieldSpec.builder(typeMirror,activityName).build();
int id = variableElement.getAnnotation(BindView.class).value();
methodBuilder.addStatement("tager.$N=($T)tager.findViewById($L)", name, typeMirror2, id);
}
//创建类 ==>public class MainActivity$ViewBinder implements ViewBind<MainActivity> {
TypeSpec typeSpec = TypeSpec.classBuilder(activityName + "$ViewBinder")
.addModifiers(Modifier.PUBLIC)
.addSuperinterface(interface_Parame)//添加接口,接口泛型==》 ViewBind<MainActivity>
.addMethod(methodBuilder.build())
.build();
//创建文件
JavaFile javaFile = JavaFile.builder(packageName, typeSpec)
.addFileComment("注解处理器生成的类\n")
//通过注释打印几个Element
.addFileComment(enclosingElement.getEnclosingElement().toString() + "\n")
.addFileComment(enclosingElement.toString() + "\n")
.addFileComment(enclosingElement.getEnclosedElements().toString() + "\n")
.addFileComment(classElement.getSuperclass() + "\n") //拿到继承的父类
.addFileComment(classElement.getInterfaces() + "\n") //拿到接口
.addFileComment(classElement.getSimpleName() + "\n") //拿到类名MainActivity
.addFileComment(classElement.getEnclosingElement().toString() + "\n") //拿到类名MainActivity
// .addStaticImport(className) //添加 import .....
.build();
try {
javaFile.writeTo(processingEnv.getFiler());
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
//获取map key/value==》activity/成员变量list
private void getMap(Map<String, List<VariableElement>> map, Set<? extends Element> elements) {
for (Element element : elements) {
VariableElement variableElement = (VariableElement) element;
//getEnclosingElement 获取上一个节点 ,用于获取类名
String activityName = variableElement.getEnclosingElement().getSimpleName().toString();
List<VariableElement> list_field = map.get(activityName);
if (list_field == null) {
list_field = new ArrayList<>();
map.put(activityName, list_field);
}
list_field.add(variableElement);//field -> list -> map
}
}
}
2.在处理的module的main目录下创建:javax.annotation.processing.Processor文件,填入处理器路径
创建原因好像是Gradle版本问题,没有该文件执行执行后没有生产java文件
文件内容:
使用注解处理器:
创建ButterKnife类,ViewBind接口:注解处理器创建的java类是实现该接口,然后利用重载,传递给不同Activity的处理器类,控件的初始化才能生效
配置build.gradle:
注意!annotationProcessor表示注解处理器依赖,如果用implementation就会报错
一个module一个注解处理器,如:lib_complier2是另外一个处理器,同样annotationProcessor
注意!如果想将注解和注解处理器写在同一个module,然后只依赖一个module那是不行的!理由太复杂
Activity中使用
@BindView(R.id.texxt)
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BufferKnife2.bind(this);
textView.setText("Hello JavaPoet!");
VindBind接口:泛型T为Activity
public interface ViewBind<T> {
void bind(T target);
}
ButterKnife
public class BufferKnife2 {
public static void bind(Activity activity){
String name=activity.getClass().getName()+"$ViewBinder";
//MainActivity$ViewBinder 拿到自动注解生成的类名,
try {
ViewBind viewBind= (ViewBind) Class.forName(name).newInstance();
viewBind.bind(activity);
} catch (Exception e) {e.printStackTrace();}}}
Rebuild一下应该就能生成java路径:build/generated/source/apt/debug/包名/MainActivity$ViewBinder
package com.zzn.test5555555;
import android.widget.TextView;
public class MainActivity$ViewBinder implements ViewBind<MainActivity> {
public void bind(MainActivity tager) {
tager.textView=(TextView)tager.findViewById(2131165319);
}
}