Android 编译时注解(Annotation Processing)

Android编译时注解

APT(Annotation Processing Tool)注解处理器,编译过程中读源码,然后生成新的代码文件,再放在一起进行编译

用反射实现 butterknife
创建 @BindView 注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface BindView {
    int value();
}

通过反射获取 Filed[],找到添加了 @BindView 的字段,调用 findViewById() 来给指定 View 绑定赋值
public class Binding {

    /**
     * 通过反射绑定View视图Id
     * @param activity
     */
    public static void bind(Activity activity) {
        Field[] fields = activity.getClass().getDeclaredFields();
        for (Field field : fields) {
            BindView bindView = field.getAnnotation(BindView.class);
            if (bindView != null) {
                try {
                    field.setAccessible(true);// 私有字段强制反射
                    field.set(activity, activity.findViewById(bindView.value()));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

依赖注入

把依赖的决定权交给外部,即依赖注入

Dagger:外部的依赖图决定依赖的值,对象自己只负责索要,而不负责指定值,所以Dagger是依赖注入

ButterKnife:自己决定依赖的获取,只是把执行过程交给了 ButterKnife,所以ButterKnife只是一个视图绑定库,而不是依赖注入


用 Annotation Processing 实现 butterknife
创建 lib-annotations 的 java-library 库,用于编写注解代码

创建 @BindView 注解

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface BindView {
    int value();
}

创建 lib-processor 的 java-library 库

添加依赖

dependencies {
    implementation project(':lib-annotations')
    implementation 'com.squareup:javapoet:1.12.1'// 用于生成java文件
}

创建注解处理器,继承AbstractProcessor

在编译期,对使用了 @BindView 的 XXActivity 对应生成一个 XXActivityBinding 的 java 文件

public class BindingProcessor extends AbstractProcessor {

    Filer filer;

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

  	// 处理注解
  	// annotations:程序中出现已注册的Annotations
  	// roundEnv:各个java文件
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        //System.out.println("process run!");
        for (Element element: roundEnv.getRootElements()) {
            String packageStr = element.getEnclosingElement().toString();// 包名
            String classStr = element.getSimpleName().toString();// 类名
            ClassName className = ClassName.get(packageStr, classStr + "Binding");
            MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()
                    .addModifiers(Modifier.PUBLIC)
                    .addParameter(ClassName.get(packageStr, classStr), "activity");

            boolean hasBinding = false;
            for (Element element2 : element.getEnclosedElements()) {
                if (element2.getKind() == ElementKind.FIELD) {// 是加了注解的字段
                    BindView bindView = element2.getAnnotation(BindView.class);// 获取注解
                    if (bindView != null) {
                        hasBinding = true;
                        constructorBuilder.addStatement("activity.$N = activity.findViewById($L)"
                                , element2.getSimpleName(), bindView.value());
                    }
                }
            }

            TypeSpec classBuilder = TypeSpec.classBuilder(className)
                    .addModifiers(Modifier.PUBLIC)
                    .addMethod(constructorBuilder.build())
                    .build();
            if (hasBinding) {
                try {
                    JavaFile.builder(packageStr, classBuilder)
                            .build()
                            .writeTo(filer);// 构造出文件并写到指定位置
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
        return false;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {// 支持的注解,必须重写
        return Collections.singleton(BindView.class.getCanonicalName());
    }
}

配置注解处理器

在main下新建 resources/META-INF/services/javax.annotation.processing.Processor 文件

文件内容为 BindingProcessor 的包名 + “.” + 类名,比如:com.chen.lib_processor.BindingProcessor


创建 lib-bindview 的 android-library 库

添加依赖

api project(':lib-annotations')

创建Binding,通过反射调用编译期生成的 XXActivityBinding

public class Binding {

    /**
     * 通过反射调用 XXActivity 对应的 XXActivityBinding 构造方法
     *
     * @param activity
     */
    public static void bind(Activity activity) {
        try {
            Class<?> bindingClass = Class.forName(activity.getClass().getCanonicalName() + "Binding");
            Constructor<?> constructor = bindingClass.getDeclaredConstructor(activity.getClass());
            constructor.newInstance(activity);
        } catch (ClassNotFoundException
                | NoSuchMethodException
                | InvocationTargetException
                | IllegalAccessException
                | InstantiationException e) {
            e.printStackTrace();
        }
    }

}

在 app 模块中使用

添加依赖

implementation project(':lib-bindview')
annotationProcessor project(':lib-processor')

在Activity中使用

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.layout)
    ConstraintLayout layout;
    @BindView(R.id.textView)
    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Binding.bind(this);

        layout.setBackgroundColor(Color.CYAN);
        textView.setText("Hello BindView");
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值