一句话说透Android里面的编译器注解APT的使用及其原理

4 阅读3分钟

一句话总结:
APT(注解处理器)就像代码生成的“秘书”——你在代码里贴标签(注解),它编译时扫描标签,按你的指令自动生成新代码,省去手写重复代码的麻烦!


一、APT 是什么?

  • 官方解释:  Annotation Processing Tool(注解处理工具),在 编译时 扫描和处理代码中的注解,生成新代码。
  • 人话翻译:  你写几个注解标记需要生成代码的地方,APT 在编译时自动帮你生成对应的 Java 文件(如 ButterKnife 的 View 绑定代码)。

二、APT 使用步骤(手把手教学)

1. 定义注解(贴标签)

创建一个 Java 模块,定义自定义注解:

// @BindView 注解示例  
@Retention(RetentionPolicy.CLASS) // 保留到编译时  
@Target(ElementType.FIELD)        // 作用在字段上  
public @interface BindView {  
    int value(); // 接收 View 的 ID  
}  

2. 实现注解处理器(秘书的工作手册)

创建一个 Java 模块,实现 AbstractProcessor

public class BindViewProcessor extends AbstractProcessor {  
    // 指定支持的注解类型  
    @Override  
    public Set<String> getSupportedAnnotationTypes() {  
        return Collections.singleton(BindView.class.getCanonicalName());  
    }  

    // 处理注解,生成代码  
    @Override  
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {  
        for (Element element : env.getElementsAnnotatedWith(BindView.class)) {  
            // 解析注解,生成如 "MainActivity_ViewBinding.java" 的代码  
            generateBindingCode(element);  
        }  
        return true;  
    }  
}  

3. 注册处理器(告诉秘书联系方式)

在处理器模块的 resources/META-INF/services 目录下创建文件 javax.annotation.processing.Processor,内容为处理器类名:

com.example.BindViewProcessor  

4. 在项目中使用(贴标签,等秘书生成代码)

在 Activity 中使用注解:

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

编译后,APT 自动生成类似下面的代码:

public class MainActivity_ViewBinding {  
    public static void bind(MainActivity activity) {  
        activity.textView = activity.findViewById(R.id.text_view);  
    }  
}  

三、APT 核心原理(秘书的工作流程)

  1. 编译时触发:  当 Java 编译器(javac)开始工作时,APT 自动启动。
  2. 扫描注解:  遍历所有源码和 Class 文件,找到被目标注解标记的元素(如字段、方法)。
  3. 生成代码:  根据注解信息,用 JavaPoet 等工具生成新的 Java 文件。
  4. 多轮处理:  生成的代码可能包含新注解,APT 会多次循环处理,直到无新代码生成。

四、APT 的优缺点(秘书的优缺点)

优点缺点
编译时处理,不拖慢运行时学习成本高,需理解注解处理 API
减少手写重复代码(如 findViewById)生成的代码调试困难
代码更干净,维护方便配置稍繁琐(注册处理器)

五、APT 应用场景(秘书能帮你干啥)

  1. View 绑定:  如 ButterKnife,自动生成 findViewById 代码。
  2. 依赖注入:  如 Dagger2,生成依赖注入逻辑。
  3. 路由框架:  如 ARouter,生成 Activity 路由表。
  4. 序列化/反序列化:  如 Gson TypeAdapter 自动生成。

六、APT vs 反射(秘书 vs 临时工)

APT(编译时生成)反射(运行时处理)
性能高,无运行时开销性能低,反射调用慢
代码可见,易调试代码隐藏,调试困难
需提前生成代码动态处理,灵活但风险高

口诀:
“APT 秘书编译忙,注解标签贴妥当,
生成代码省人力,性能优化无损伤,
配置注册别忘记,ButterKnife 同款强!”

附:APT 工作流程图

写注解 → 编译 → APT 扫描 → 生成代码 → 二次编译 → 最终 APK