Android 利用Annotation Processing 编译时通过注解自动生成代码

类似ButterKnife的框架,因为时间有限只实现绑定View.主要是利用 Annotation Processing,编译的过程中读取注解,然后使用JavePoet生成我们想要的代码

项目结构

lib是一个Android Library,lib_annotation,lib_processor只需要是Java Library

依赖关系


左侧的的依赖是可以传递的

app

    implementation project(":lib")    annotationProcessor project(":lib_processor")

lib

 api project(":lib_annotation")  //因为依赖要传递到app中,所以要用api

lib_processor

    //自动生成代码的库    implementation 'com.squareup:javapoet:1.11.1'    //自动生成service,省去了配置resources/META-INF/services,配合@AutoService(Processor.class)使用    implementation 'com.google.auto.service:auto-service:1.0-rc4'    implementation project(':lib_annotation')

我们需要自动生成代码的样式

我们要自动生成这样的代码,代替我们findViewById的繁琐操作

public class MainActivity$Binding {  public MainActivity$Binding(MainActivity activity) {    activity.mTextView = activity.findViewById(2131165319);  }}

实现BindProcessor

  1. 首先要继承AbstractProcessor
  2. 在java同级目录下创建resources/META-INF/services/javax.annotation.processing.Processor文件
    com.lixxy.lib_processor.BindProcessor
    或者
    //自动生成service,省去了配置resources/META-INF/servicesimplementation 'com.google.auto.service:auto-service:1.0-rc4'//还需要在BindProcessor加注解@AutoService(Processor.class)@AutoService(Processor.class)public class BindProcessor extends AbstractProcessor {}

BindProcessor类

@AutoService(Processor.class)public class BindProcessor extends AbstractProcessor {    //获取操作文件的工具    private Filer mFiler;    @Override    public synchronized void init(ProcessingEnvironment processingEnvironment) {        super.init(processingEnvironment);        mFiler = processingEnvironment.getFiler();    }    /**     * @param set              是 getSupportedAnnotationTypes返回的set     * @param roundEnvironment 运行注解所在的环境     * @return     */    @Override    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {        //运行注解所在的环境class 此处就是testActivity        Set<? extends Element> rootElements = roundEnvironment.getRootElements();        for (Element rootElement : rootElements) {            //运行注解所在的环境.java所在的包            String packageStr = rootElement.getEnclosingElement().toString();            String classStr = rootElement.getSimpleName().toString();            ClassName className = ClassName.get(packageStr, classStr + "$Binding");            MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()                    .addModifiers(Modifier.PUBLIC)                    .addParameter(ClassName.get(packageStr, classStr), "activity");            boolean isBind = false;            //运行注解所在的环境.java的成员  包括成员字段Field,方法,内部类等            List<? extends Element> enclosedElements = rootElement.getEnclosedElements();            for (Element enclosedElement : enclosedElements) {                //如果是字段                if (enclosedElement.getKind().isField()) {                    BindView bindView = enclosedElement.getAnnotation(BindView.class);                    //如果是被BindView注解的字段                    if (bindView != null) {                        isBind = true;                        //增加构造方法的内容                        // $N是名称替换  $L 字面量替换 也就是直接替换,具体的看Javapoet的使用方法                        constructorBuilder.addStatement("activity.$N = activity.findViewById($L)", enclosedElement.getSimpleName(), bindView.value());                    }                }            }            TypeSpec typeSpec = TypeSpec.classBuilder(className)                    .addModifiers(Modifier.PUBLIC)                    .addMethod(constructorBuilder.build())                    .build();            if (isBind) {                try {                    JavaFile.builder(packageStr, typeSpec)                            .build().writeTo(mFiler);                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return false;    }    /**     * 这个注解处理器是注册给哪个注解的     * 注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。     * 换句话说,你在这里定义你的注解处理器注册到哪些注解上     */    @Override    public Set getSupportedAnnotationTypes() {        super.getSupportedAnnotationTypes();        return Collections.singleton(BindView.class.getCanonicalName());    }}

实现注解

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Retention(RetentionPolicy.SOURCE)  //只在编译期生效@Target(ElementType.FIELD) //只对字段生效public @interface BindView {    int value();  }

实现Bind类

public class Bind {    publicstatic void bind(Activity activity) {    //在这里对activity中的字段进行负值或者调用负值的方法    //使用反射的方法调用我们自动生成的类     try {            //获取class对象            Class<?> bindClass = Class.forName(activity.getClass().getCanonicalName() + "$Binding");            // 获取有参数的构造方法(构造方法的参数)            Constructor<?> constructor = bindClass.getDeclaredConstructor(Class.forName(activity.getClass().getCanonicalName()));            //调用构造方式            constructor.newInstance(activity);        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (NoSuchMethodException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        }    }}

项目中使用

 @BindView(R.id.textView)    TextView mTextView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Bind.bind(this);        mTextView.setText("Bind Success!!!");    }

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. android上一些方法的区别和用法的注意事项
  5. android实现字体闪烁动画的方法
  6. Android中dispatchDraw分析
  7. Android四大基本组件介绍与生命周期
  8. Android(安卓)MediaPlayer 常用方法介绍
  9. 在Fragment中设置控件点击方法,执行失败。

随机推荐

  1. 源码解析Android中AsyncTask的工作原理
  2. 【Android游戏开发二十一】Android(安卓)
  3. Android(安卓)View 属性大全
  4. Android(安卓)SDK 2.1 下载与安装教程
  5. android 网络 post get
  6. 关于Linearlayout中控件设置为其底部的问
  7. 【Android】Android的快速开发框架Afinal
  8. Android消息处理系统
  9. Android各版本及API对应关系,持续更新!
  10. [原创] Android(安卓)Activity onNewInte