apt是编译期还是运行期生效的?
apt和aspectj有什么区别?
Android Databinding
、Butterknife
、Dagger2
、ARouter
你也许在用,它们是怎么实现的呢?
看过本文,也许你也能写出一个Dagger2
,你知道它并没有用到哪些你不能理解的黑科技。
一、apt原理
什么是apt?
apt就是javac对外开放的一个插件,使javac在编译期间根据注解(Annotation)获取相关数据 。

更多Android相关流程图请移步andych008/flow_chart)
apt能干什么?
通过这个插件,多数情况下我们会在编译过程中生成java文件。最终我们通过工具类调用这些生成的代码(有些时候工具类通过反射自动完成这一步),完成一些重复性的工作。
比如:
- Android Databinding绑定view
activity_main.xml
会生成ActivityMainBinding.java
。调用工具类的
android.databinding.DataBindingUtil.setContentView(this, R.layout.activity_main);
完成数据绑定 - Butterknife绑定view
MainActivity
会生成MainActivity?ViewBinder<T extends MainActivity> implements ViewBinder<T>
调用工具类的
ButterKnife.bind(this);
完成绑定 - Dagger2注入变量
BackCamara
的构造方法加注解@Inject public BackCamera() {}
生成BackCamera_Factory
Phone
的成员加注解@Inject public BackCamera mCamera;
生成Phone_MembersInjector
Component
接口加注解@Component public interface PhoneComponent
生成DaggerPhoneComponent
调用工具类的
DaggerPhoneComponent.create().inject(this);
完成注入。 - ARouter生成路由表
apt不能干什么?
apt不能修改已有代码的执行流程,如果要实现类似“日志打点”等在原代码的基础上插入一些功能,一般需要通过aspectj来实现。这类功能是在编译后期(javac之后)修改字节码文件来实现。
apt怎么参与到javac的编译过程的?
apt与javac约定在META-INF/services/javax.annotation.processing.Processor
文件中注册apt插件。
知道了apt的工作原理,再学习它的使用,会是一件很easy的事件情。
apt的使用,见最下面的 Demo源码
二、开发相关
apt为什么得远程调试
www.jianshu.com/p/cb0256633…
./gradlew --no-daemon -Dorg.gradle.debug=true :app:clean :app:compileDebugJavaWithJavac
因为apt代码执行在编译器所在的进程
向apt程序传参
@SupportedOptions({ "debug" })
boolean isDebug = Boolean.parseBoolean(processingEnv.getOptions().get("debug"));
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [debug: "true"]
}
}
}
}
三、扩展阅读1
很多时候,我们写apt插件,都会引入@AutoService
和JavaPoet
来提升开发效率。
@AutoService
的工作原理
@AutoService
本质上也是一个apt插件,我们的apt插件通过注解的方式@AutoService(javax.annotation.processing.Processor.class)
注册到@AutoService
里。@AutoService
在编译期为我们的apt插件生成META-INF/services/javax.annotation.processing.Processor
文件,帮助我们完成注册。- 因为javac对注解处理是循环解析、编译,所以
@AutoService
的方式是可行的。
JavaPoet
的作用
JavaPoet
的作用就是帮助我们生成java源文件,核心类CodeWriter.java
比如Butterknife生成MainActivity?ViewBinder,使用到了JavaPoet
,否则只能通过拼接字符串的方式(如下面Demo源码的master分支)。不但提高了开发效率,而且代码的可读性更好,见ButterKnifeProcessor.java。
Demo源码
mydev分支在master基础上引入@AutoService
和JavaPoet
。建议无基础的朋友,先学习master分支。在此先感谢master分支的作者LiMubai2017
四、扩展阅读2
和apt相关的知识,当然是aspectj和ASM了。当然还有gradle Transform Api。这些,以后再聊。