apt不再神秘

1,947 阅读3分钟

apt是编译期还是运行期生效的?

apt和aspectj有什么区别?

Android DatabindingButterknifeDagger2ARouter你也许在用,它们是怎么实现的呢?

看过本文,也许你也能写出一个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注入到Phone为例

    BackCamara的构造方法加注解@Inject public BackCamera() {}生成BackCamera_Factory

    Phone的成员加注解@Inject public BackCamera mCamera;生成Phone_MembersInjector

    Component接口加注解@Component public interface PhoneComponent生成DaggerPhoneComponent

    调用工具类的DaggerPhoneComponent.create().inject(this);完成注入。

  • ARouter生成路由表

    RouteProcessor.java

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插件,都会引入@AutoServiceJavaPoet来提升开发效率。


@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基础上引入@AutoServiceJavaPoet。建议无基础的朋友,先学习master分支。在此先感谢master分支的作者LiMubai2017

四、扩展阅读2

和apt相关的知识,当然是aspectj和ASM了。当然还有gradle Transform Api。这些,以后再聊。