20210906 - 底层技术 - 注解与注解处理器

20210906 - 底层技术 - 注解与注解处理器,第1张

20210906 - 底层技术 - 注解与注解处理器 20210906 - 底层技术 - 注解与注解处理器 注解语法
@Target({ElementType.FIELD, ElementType.METHOD})// 作用在什么地方
@Retention(RetentionPolicy.RUNTIME)							// 作用范围
public @interface BindView {
    String value();
    int id();
}

public enum ElementType {
    TYPE,               
    FIELD,              
    METHOD,             
    PARAMETER,          
    CONSTRUCTOR,        
    LOCAL_VARIABLE,     
    ANNOTATION_TYPE,    
    PACKAGE             
}

public enum RetentionPolicy {
    SOURCE,            
    CLASS,             
    RUNTIME            
}
@IntDef代替枚举
class Test {
    private static final int SUNDAY = 0;
    private static final int MonDAY = 1;

    // 注解代替枚举,可以节省内存空间
    @IntDef({SUNDAY, MONDAY})
    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.SOURCE)
    @interface WeekDay{
    }

    public static void setCurrDay(@WeekDay int currDay) {
    }

    public static void main(String[] args) {
        setCurrDay(SUNDAY);
    }
}
APT注解处理器使用

javac 把 java 文件编译成 class 文件,APT就是作用在javac上。

1、新建一个名为 annotation_compiler 的 java library 工程

2、annotation_compiler 工程的 gradle 中添加如下依赖

// 在 java library 的 gradle 文件中添加如下:
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
compileonly 'com.google.auto.service:auto-service:1.0-rc4'

3、开始注解处理器编码

@AutoService(Processor.class)
public class AnnotationsCompiler extends AbstractProcessor {
    // 1.支持的版本
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    // 2.能用来处理哪些注解
    @Override
    public Set getSupportedAnnotationTypes() {
        // 只能处理 @BindView 类型的注解    
        Set types = new HashSet<>();
        types.add(BindView.class.getCanonicalName());
        return types;
    }
  
    // 3.定义一个用来生成APT目录下面的文件的对象
    Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        filer = processingEnvironment.getFiler();
    }
  
    // 4、处理逻辑,生成所需的代码
    @Override
    public boolean process(Set set, RoundEnvironment roundEnvironment) {
      	// 日志打印
      	processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "jett---------------" + set);
      
        return false;
    }
}
APT实现butterknife实战 1、新建一个 java-library 类型的注解工程 “annotation”
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface BindView {
    int value();
}
2、新建一个 application 类型工程
public interface IBinder {
    void bind(T target);
}

public class JettButterknife {
    public static void bind(Activity activity) {
        String name = activity.getClass().getName() + "_ViewBinding";
        try {
            Class aClass = Class.forName(name);
            IBinder iBinder = (IBinder) aClass.newInstance();
            iBinder.bind(activity);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class MainActivity extends AppCompatActivity {
    @BindView(R.id.tvText)
    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        JettButterknife.bind(this);
        textView.setText("你好");
    }
}

// gradle 文件中添加如下依赖:
implementation project(path: ':annotations')
annotationProcessor project(path: ':annotation_compiler')
3、目的是在 application 工程的 /build/generated/ap_generated_sources/debug/out/... 路径下生成如下代码:
package com.example.dn_butterknife;

import com.example.dn_butterknife.IBinder;

public class MainActivity_ViewBinding implements IBinder {
    @Override
    public void bind(com.example.dn_butterknife.MainActivity target) {
        target.textView = (android.widget.TextView) target.findViewById(2131165359);
    }
}
4、因此 APT 工程的代码应该这么编码

新建 java-ibrary 类型的 annotation_compiler 工程

package com.example.annotation_compiler;

import com.example.annotations.BindView;
import com.google.auto.service.AutoService;
import com.google.errorprone.annotations.Var;

import java.io.Writer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
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.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;

@AutoService(Processor.class)
public class AnnotationsCompiler extends AbstractProcessor {
    Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        filer = processingEnvironment.getFiler();
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public Set getSupportedAnnotationTypes() {
        Set types = new HashSet<>();
        types.add(BindView.class.getCanonicalName());
        return types;
    }

    @Override
    public boolean process(Set set, RoundEnvironment roundEnvironment) {
        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "jett---------------" + set);

        // 1、获取APP中所有用到了BindView注解的对象
        Set elementsAnnotatedWith = 
          	roundEnvironment.getElementsAnnotatedWith(BindView.class);


        // 2、开始对elementsAnnotatedWith进行分类
        // 
        // Element 的子类有如下:
        //
        // TypeElement //类
        // ExecutableElement //方法
        // VariableElement //属性
        //
        Map> map = new HashMap<>();
        for (Element element : elementsAnnotatedWith) {
            // @BindView 是属性类型,所以直接强转        
            VariableElement variableElement = (VariableElement) element;
            // 获取 @BindView 所在的作用域,也就是Activity类,拿到Activity的名称
            String activityName = variableElement.getEnclosingElement().getSimpleName().toString();
            // 获取 @BindView 所在的作用域,也就是Activity类,拿到Activity的字节码对象
            Class aClass = variableElement.getEnclosingElement().getClass();
            // [
            //   "MainActivity" : {VariableElement1, VariableElement2, ...}
            //   "TwoActivity" : {VariableElement1, VariableElement2}
            //   "ThreeActivity" : {VariableElement1}
            // ]
            List variableElements = map.get(activityName);
            if (variableElements == null) {
                variableElements = new ArrayList<>();
                map.put(activityName, variableElements);
            }
            variableElements.add(variableElement);
        }


        // 3、开始生成文件
        //
        // package com.example.dn_butterknife;
        // import com.example.dn_butterknife.IBinder;
        // public class MainActivity_ViewBinding implements IBinder {
        //     @Override
        //     public void bind(com.example.dn_butterknife.MainActivity target) {
        //         target.textView = (android.widget.TextView) target.findViewById(2131165359);
        //     }
        // }
        //
        if (map.size() > 0) {
            Writer writer = null;
            for (String activityName : map.keySet()) {
                // 拿到某个 Activity 中的所有注解
                List variableElements = map.get(activityName);
                // 拿到包名
                TypeElement enclosingElement = (TypeElement) variableElements.get(0).getEnclosingElement();
                String packageName = processingEnv.getElementUtils().getPackageOf(enclosingElement).toString();
                try {
                    // 开始生成 MainActivity_ViewBinding.java 文件
                    // 创建名为 com.example.dn_butterknife.MainActivity 的.java文件               
                    JavaFileObject sourceFile = filer.createSourceFile(packageName + "." 
                                                                       + activityName + "_ViewBinding");
                    writer = sourceFile.openWriter();
                    // package com.example.dn_butterknife;
                    writer.write("package " + packageName + ";n");
                    // import com.example.dn_butterknife.IBinder;
                    writer.write("import " + packageName + ".IBinder;n");
                    // public class MainActivity_ViewBinding implements IBinder
                    // 									{
                    writer.write("public class " + activityName + "_ViewBinding implements IBinder<" + 
                                 packageName + "." + activityName + ">{n");
                    // @Override
                    // public void bind(com.example.dn_butterknife.MainActivity target) {
                    writer.write(" @Overriden" +
                            " public void bind(" + packageName + "." + activityName + " target){");
                    // target.tvText=(android.widget.TextView)target.findViewById(2131165325);
                    for (VariableElement variableElement : variableElements) {
                        // 得到名字
                        String variableName = variableElement.getSimpleName().toString();
                        // 得到ID
                        int id = variableElement.getAnnotation(BindView.class).value();
                        // 得到类型
                        TypeMirror typeMirror = variableElement.asType();
                        writer.write("target." + variableName + "=(" + typeMirror + ")target.findViewById(" 
                                     + id + ");n");
                    }
                    // }}
                    writer.write("n}}");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (writer != null) {
                        try {
                            writer.close();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return false;
    }
}


// 在 gradle 文件中添加如下依赖:
// annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
// compileonly 'com.google.auto.service:auto-service:1.0-rc4'

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5076718.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-16
下一篇 2022-11-16

发表评论

登录后才能评论

评论列表(0条)

保存