ARouter——原理分析整理

ARouter

概述

在每个需要对其他module提供调用的Activity中,都要声明类似下面@Route注解,我们称之为路由地址。

@Route(path = "/main/main")
public class MainActivity extends AppCompatActivity {
   }
@Route(path = "/module1/module1main")
public class Module1MainActivity extends AppCompatActivity {
   }

现在我们有三个module

  • APP——主工程
  • QRCode——扫码Module
  • Gallery——项目模块

对于其他module需要使用ARouter跳转至QRCode Activity时

我们需要声明一个QRCode Activity的路由地址

public static final String QRCODE_SCAN_PATH = "/qrcode/scan";

然后在对应的QRCode的Activity上添加注解

@Route(path = RouteHub.QRCode.QRCODE_SCAN_PATH)

然后调用以下方法就可以完成跳转了

ARouter.getInstance().buildRouteHub.QRCode.QRCODE_SCAN_PATH).navigation(this)

这样,两个模块不用相互有任何直接的依赖,就可以进行转跳,模块与模块之间就相互独立了。

原理

APT

ARouter的使用非常方便,得益于APT。

APT的作用是在编译阶段扫描并处理代码中的注解,然后根据注解输出Java文件。

ARouter为了方便实现注解处理器还额外用了两个库。

一个是JavaPoet,他提供了调用对象方法的方式生成需要的代码,而不再需要人为的用StringBuilder去拼接代码,再使用IO写入文件。

第二个是Auto-Service,他提供了简便的方式去注册APT,避免了原本繁琐的注册步骤。

@Route

Route的定义:

@Target({
   ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Route{
   
    /**
     * Path of route
     */
    String path();
    ……
}
  • @Target({ElementType.TYPE})——表示这个annotation是修饰类的
  • @Retention(RetentionPolicy.CLASS)——表示需要保留到编译时

Route中有一个主要的参数path,他表示了Activity的路由地址。

@Route(path = RouteHub.QRCode.QRCODE_SCAN_PATH)

这样编译时能获取到Route所注解的类,并且能获取到path路径。

RouteProcessor

RouteProcessor是对@Route处理的地方。

@AutoService(Processor.class)
@SupportedAnnotationTypes({
   ANNOTATION_TYPE_ROUTE, ANNOTATION_TYPE_AUTOWIRED})
public class RouteProcessor extends BaseProcessor

解释

  • auto-service——这个库为Processor完成了自动注册
  • @SupportedAnnotationTypes({ANNOTATION_TYPE_ROUTE, ANNOTATION_TYPE_AUTOWIRED})——表明了当前Processor是出里那些注释的

RouteProcessor继承于BaseProcessor,在init方法中获取到了每个模块的moduleName。


// Attempt to get user configuration [moduleName]
Map<String, String> options = processingEnv.getOptions();
if (MapUtils.isNotEmpty(options)) {
   
  moduleName = options.get(KEY_MODULE_NAME);
  …………
}

RouteProcessor的process方法是对注解处理的地方,它直接获取了所有Route注解的元素。

Set<? extends Element> routeElements = roundEnv.getElementsAnnotatedWith(Route.class);

拿到被标注的元素后就会进入this.parseRoutes(routeElements);方法。这个方法使用JavaPoet生成Java文件。如果不用这个库我们也可以使用StringBuilder去写Java文件的内容。

我们先来看看他生成的类。

IRouteGroup


public class ARouter$$Group$$qrcode implements IRouteGroup {
   
  @Override
  public void loadInto(Map<String,RouteMeta> atlas) {
   
    atlas.put("/qrcode/scan",
      RouteMeta.build(
        RouteType.ACTIVITY, 
        ScanQRActivity.class,
        "/qrcode/scan", 
        "qrcode", 
        new java.util.HashMap<String,Integer>(){
   {
   put("tag", 8); }}, -1, -2147483648));
  }
}

关于RouteMeta: RouteMeta是包含了@Route所注解的元素的必要信息,最明显的就是ScanQRActivity.class,有了它,我们就可以通过Intent跳转到这个Activity了。

ARouter$$Group$$qrcode这个类继承自IRouteGroup ,他实现了接口中的loadInto方法。

loadInto方法逻辑很简单,传入一个map,将注解的path值作为key,将元素(RouteMeta)作为value作为Value放入map。

如果完成了这个方法,就完成了Activity的注册。

IRouteRoot

RouteProcessor还产生了ARouter$$Root$$qrcode这个类

public class ARouter$$Root$$qrcode implements IRouteRoot {
   
  @Override
  public void loadInto(Map<String,Class<? extends IRouteGroup>> routes) {
   
    routes.put("qrcode",ARouter$$Group$$qrcode.class);
  }
}

它实现了IRouteRoot接口,内容非常相似。通过loadInto方法,往Map中插入以group名为Key,IRouteGroup实现类为Value的内容。

group默认就是path中第一个斜杠之后的内容(@Route(path="/group/xxx"))

如果调用了这个方法,那么可以通过group拿到IRouteGroup实现类的class,有了class实例化之后就能通过前面所说的拿到Activity.class了。

整体的结构是下图的样子

在这里插入图片描述

我们看到,其实直接可以从IRouteGroup 传入的Map获得我们的RouteMeta,那么为什么还需要IRouteRoot的loadInto再把IRouteGroup放到Map里呢。这个大家后面就会知道。

process

回过头来再看RouteProcessor的process方法:

public boolean process(Set<? extends TypeElement> annotations, RoundEnvironmentroundEnv) {
   
  if(CollectionUtils.isNotEmpty(annotations
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值