1.声明注解
创建一个名字为apt-annotation的javalib,并在lib里创建一个BindView
注解
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface BindView {
int value();
}
2.继承AbstractProcessor实现自己的注解处理类
创建另外一个名为apt-processor的javalib,在lib中创建MyProcessor 来根据注解动态生成代码
package com.example.apt_processor;
import com.example.apt_annotation.BindView;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
import javax.swing.JList;
import javax.tools.Diagnostic;
//必须写的,用来声明这个类是注解处理类
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
//必须在javalib中创建否则无法继承AbstractProcessor类
public class MyProcessor extends AbstractProcessor {
private Elements elementUtils;
private Map<TypeElement, List<VariableElement>> map = new HashMap<>();
private Messager messager;
private Filer filer;
//返回要处理的注解 可以添加多个
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> set = new HashSet<>();
set.add(BindView.class.getCanonicalName());
return set;
}
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,"init()");
//日志打印工具
messager = processingEnv.getMessager();
elementUtils = processingEnv.getElementUtils();
//用于生成类文件
filer = processingEnv.getFiler();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
//拿到所有添加BindView注解的成员变量
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(BindView.class);
messager.printMessage(Diagnostic.Kind.NOTE,"111111111111111");
//如果set的长度为0则不处理返回false,这里这样处理是因为process方法并不是只调用一次,所以要进行过滤
if (set.size()<=0){
return false;
}
//for循环把每个activity中的控件放入统一list中
for (Element element : elements) {
messager.printMessage(Diagnostic.Kind.NOTE,element.getKind().toString());
PackageElement packageElement = elementUtils.getPackageOf(element);
messager.printMessage(Diagnostic.Kind.NOTE," getQualifiedName = "+packageElement.getQualifiedName().toString());
VariableElement variableElement = (VariableElement) element;
TypeElement typeElement = (TypeElement) variableElement.getEnclosingElement();
List<VariableElement> list = map.get(typeElement);
if (list == null){
list = new ArrayList<>();
map.put(typeElement,list);
}
Name simpleName = variableElement.getSimpleName();
BindView annotation = variableElement.getAnnotation(BindView.class);
messager.printMessage(Diagnostic.Kind.NOTE," simpleName = "+simpleName.toString());
list.add(variableElement);
}
//for循环生成每个activity对应的view绑定工具类
for (TypeElement typeElement : map.keySet()) {
String className = typeElement.getSimpleName().toString();
String packageName = elementUtils.getPackageOf(typeElement).getQualifiedName().toString();
String finalClassName = className+"Binding";
messager.printMessage(Diagnostic.Kind.NOTE,"类名 = "+finalClassName);
ClassName classType = ClassName.bestGuess(className);
String paramName = "activity";
MethodSpec.Builder builder = MethodSpec.methodBuilder("bind")
.addModifiers(Modifier.PUBLIC,Modifier.STATIC)
.returns(void.class)
.addParameter(classType,paramName);
List<VariableElement> variableElements = map.get(typeElement);
for (int i = 0; i < variableElements.size(); i++) {
VariableElement variableElement = variableElements.get(i);
String type = variableElement.asType().toString();
int viewId = variableElement.getAnnotation(BindView.class).value();
String name = variableElement.getSimpleName().toString();
builder.addStatement("$L.$L = ($L)$L.findViewById($L)",paramName,name,type,paramName,viewId);
}
MethodSpec methodSpec = builder.build();
TypeSpec typeSpec = TypeSpec.classBuilder(finalClassName)
.addModifiers(Modifier.PUBLIC)
.addMethod(methodSpec)
.build();
JavaFile javaFile = JavaFile.builder(packageName,typeSpec).build();
try {
javaFile.writeTo(filer);
messager.printMessage(Diagnostic.Kind.NOTE,"3333");
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
}
plugins {
id 'java-library'
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
dependencies{
//自动注册,动态生成 META-INF/...文件
implementation 'com.google.auto.service:auto-service:1.0-rc6'
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'
//依赖apt-annotation
implementation project(':apt-annotation')
//帮助生成代码的工具
implementation 'com.squareup:javapoet:1.13.0'
}
3.app中使用
package com.example.apttest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import com.example.apt_annotation.BindView;
public class MainActivity extends AppCompatActivity {
@BindView(R.id.contentTv)
public TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainActivityBinding.bind(this);
textView.setText("77777777777");
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation project(':apt-annotation')
annotationProcessor project(':apt-processor')
}
生成的工具类代码
package com.example.apttest;
public class MainActivityBinding {
public static void bind(MainActivity activity) {
activity.textView = (android.widget.TextView)activity.findViewById(2131230834);
}
}
网友评论