zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

【Android APT】编译时技术 ( 开发编译时注解 )

Android技术开发 编译 注解 apt
2023-06-13 09:17:50 时间

文章目录

一、编译时注解


上一篇博客 【Android APT】编译时技术 ( 编译时注解 和 注解处理器 依赖库 ) 中创建并配置了 annotation 编译时注解 依赖库 和 annotation-compiler 注解处理器 依赖库 ;

本博客开始进行开发 编译时注解 依赖库 ;

开发 annotation 编译时注解 依赖库 ;

右键点击包名 , 选择 " New / Java Class " 选项 ,

在弹出的对话框中 , 选择 " Annotation " 注解对话框 , 然后输入注解名称 BindView ,

注解源码开发 :

package kim.hsl.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

元注解解析 :

使用 @Target(ElementType.FIELD) 元注解标注该 BindView 注解 , 说明该 @BindView 注解是作用于成员变量的 ;

使用 @Retention(RetentionPolicy.CLASS) 标注 BindView 注解 , 说明该注解是 编译时注解 ;

注解属性解析 :

使用 value 作为注解属性名 , 并且只有一个 注解属性 , 因此该注解在使用的时候 , 为注解属性赋值可以省略 " value = " , 直接传入注解属性值 ;

二、编译时注解 使用


注释掉之前的 ButterKnife 的 编译时注解 和 注解处理器 , 使用应用中自己开发的 编译时注解 和 注解处理器 ;

build.gradle 构建脚本 依赖库相关配置 如下 :

dependencies {

    //implementation 'com.jakewharton:butterknife:10.2.3'
    //annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'

    annotationProcessor project(path: ':annotation-compiler')
    implementation project(path: ':annotation')
}

在 MainActivity 中模仿 ButterKnife 使用 @BindView 注解 , 这是我们自定义的注解 ;

package kim.hsl.apt;

import android.os.Bundle;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import kim.hsl.annotation.BindView;

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.hello)
    TextView hello;

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

        //hello.setText("ButterKnife");
    }
}

下一步开始使用 注解处理器 , 处理上述注解 ;

注解处理器 工作机制 : 当程序在编译时 , 执行注解处理器 , 注解处理器会搜索整个程序中 , 使用到 BindView 注解的位置 , 并获取注解的相关信息 , 所在字节码文件 , 作用位置 ( 类 / 方法 / 字段等 ) ;

三、注解的保留时间


注解分类 :

① 源码期注解 : 注解保留到源码阶段 , 只有当类是 .java 文件时才能看到 , 一旦编译成 .class 字节码文件 , 该注解就消失了 , 如 @Override 仅在编译时查看父类是否有该方法 ;

② 编译时注解 : 注解保留到字节码阶段 ;

③ 运行时注解 : 注解保留到运行时 ;

源码期注解 与 编译时注解 对比示例 :

查看 MainActivity.java 源码 : 该源码中有两个注解 @BindView 和 @Override 两个注解 ;

查看 BindView 注解的源码如下 , 其中 BindView 注解是被 @Retention(RUNTIME) 修饰的 , 说明该注解是 运行时注解 , 该注解需要从源码 到 字节码 一直保留 , 知道运行时才开始解析该注解 ;

@Retention(RUNTIME) @Target(FIELD)
public @interface BindView {
  /** View ID to which the field will be bound. */
  @IdRes int value();
}

查看 Override 注解的源码如下 , 该注解被 @Retention(RetentionPolicy.SOURCE) 修饰 , 说明该注解是 源码期注解 , 注解信息仅在源码阶段保存 , 一旦编译成字节码文件 , 高注解就被删除了 ;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

编译应用后 , 查看 MainActivity.class 字节码文件 , 该字节码文件在 " APT\app\build\intermediates\javac\debug\classes\kim\hsl\apt " 目录下 ;

字节码文件中的 @Override 注解已经消失 , @BindView 注解还存在 ;

@Override 注解是 源码期注解 , 只保留到源码期 , 编译时使用该注解 , 编译完成后 , 该注解就被删除了 ;

@BindView 注解 是 运行时注解 , 该注解需要在运行时使用 , 需要一直保留到运行时 ;

四、博客资源


博客源码 :