有多简单,仅仅只有跳转功能,主要为了了解AbstractProcessor的使用

是什么

也就是常说的APT,和aapt不一样啊,不一样的东西。
是一个在javac中的,用来编译时扫描和处理的注解的工具。你可以为特定的注解,注册你自己的注解处理器。

干嘛用

比如各种路由框架,黄油刀什么的都会使用到 apt,为什么要用呢,还是为了能够生成代码,有些代码不用使用者去使用,比较方便

怎么用

先说流程,先依赖,然后需要写一个注解,一般都是根据注解来处理,其次继承AbstractProcessor,在process函数中,生成自己需要的类。

依赖

  1. implementation 'com.google.auto.service:auto-service:1.0-rc6'
  2. annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'
  3. implementation 'com.squareup:javapoet:1.10.0'
  4. compileOnly files(Jvm.current().getToolsJar())

写个注解

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.CLASS)
  3. public @interface Router {
  4. String path();
  5. }

继承AbstractProcessor

  1. @AutoService(Processor.class)
  2. @SupportedAnnotationTypes("net.mikaelzero.interfaces.Router")
  3. @SupportedSourceVersion(SourceVersion.RELEASE_8)
  4. public class UriProcessor extends BaseProcessor {
  5. @Override
  6. public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  7. super.process(annotations, roundEnv);
  8. .......
  9. return true;
  10. }
  11. }

BaseProcessor是啥,直接copy WMRouter

两个注意点,注解写在单独的module中,比如叫interfaces,处理AbstractProcessor的也写在一个单独的module中,比如叫complie,这两个都是java工程,不是android工程。

生成java文件

  1. @Override
  2. public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  3. super.process(annotations, roundEnv);
  4. if (annotations == null || annotations.isEmpty()) {
  5. return false;
  6. }
  7. CodeBlock.Builder builder = CodeBlock.builder();
  8. for (Element element : roundEnv.getElementsAnnotatedWith(Router.class)) {
  9. if (!(element instanceof Symbol.ClassSymbol)) {
  10. continue;
  11. }
  12. boolean isActivity = isActivity(element);
  13. if (!isActivity) {
  14. continue;
  15. }
  16. Symbol.ClassSymbol cls = (Symbol.ClassSymbol) element;
  17. Router uri = cls.getAnnotation(Router.class);
  18. if (uri == null) {
  19. continue;
  20. }
  21. CodeBlock handler = buildHandler(isActivity, cls);
  22. String path = uri.path();
  23. builder.addStatement("handler.register($S, $L)", path, handler);
  24. }
  25. //由于随机生成类名,需要根据接口去找对应实现类,代码量较多,作为演示,取一个固定的名字
  26. buildHandlerInitClass(builder.build(), "UriAnnotationInitImpl", Const.URI_ANNOTATION_HANDLER_CLASS, Const.URI_ANNOTATION_INIT_CLASS);
  27. return true;
  28. }

点击小锤子编译后,看看生成的文件,文件在你使用annotationProcessor compile的module中的generated中

  1. public class UriAnnotationInitImpl implements IUriAnnotationInit {
  2. public void init(UriHandler handler) {
  3. handler.register("/second", "net.mikaelzero.second.SecondActivity");
  4. }
  5. }

IUriAnnotationInit是个啥,虽然我们编写好了生成代码的策略,但是这个生成好的代码,该怎么运行?
没错,用一个接口,在通过开放一个函数(比如init什么的),在init中,对所有实现了该接口的实现类进行实例化并且调用。

最后一步

调用上面的init函数,为了追求简单,我直接在生成类的时候生成为固定的名字,然后实例化并调用init

  1. void init() {
  2. try {
  3. Class<?> clazz = Class.forName("net.mikaelzero.router.generated.UriAnnotationInitImpl");
  4. IUriAnnotationInit annotationInit = (IUriAnnotationInit) clazz.newInstance();
  5. annotationInit.init(new UriHandler());
  6. } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
  7. e.printStackTrace();
  8. }
  9. }

再看看UriHandler

  1. public class UriHandler {
  2. private static final Map<String, String> mMap = new HashMap<>();
  3. public void register(String path, String handler) {
  4. String pathHandler = mMap.get(path);
  5. if (pathHandler == null) {
  6. mMap.put(path, handler);
  7. }
  8. }
  9. public static Intent createIntent(Context context, @NonNull String path) {
  10. return new Intent().setClassName(context, mMap.get(path));
  11. }
  12. }

同样追求简单,直接写成了static,最后就是调用,并跳转了.

  1. @Router(path = "/second")
  2. public class SecondActivity extends AppCompatActivity {
  3. ......
  4. }
  5. startActivity(UriHandler.createIntent(this, "/second"));

总结

看起来好像和gradle没啥关系啊,但是gradle和asm有关系,javapoet和asm有关系

github地址 https://github.com/MikaelZero/RouterDemo