美文网首页
APT的使用

APT的使用

作者: SunnyDay_ab5f | 来源:发表于2023-05-15 15:36 被阅读0次

    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);
      }
    }
    
    

    相关文章

      网友评论

          本文标题:APT的使用

          本文链接:https://www.haomeiwen.com/subject/iomwortx.html