用简单一两句话总结出来:ARouter通过Apt技术,生成保存路径(路由path)和被注解(@Router)的组件类的映射关系的类,利用这些保存了映射关系的类,Arouter根据用户的请求postcard(明信片)寻找到要跳转的目标地址(class),使用Intent跳转。原理很简单,可以看出来,该框架的核心是利用apt生成的映射关系。
使用时,在每个需要对其他module提供调用的Activity中,都要声明类似下面@Route注解,我们称之为路由地址。
@Route(path = "/main/homepage")
public class HomeActivity extends BaseActivity {
onCreate()
....
}
然后在需要跳转的时候调用
Arouter.getInstance().build("main/hello").navigation;
这里的路径“main/hello”是用户唯一配置的东西,我们需要通过这个path找到对应的Activity。最简单的思路就是通过APT技术,寻找到所有带有注解@Router的组件,将其注解值path和对应的Activity保存到一个map里,比如像下面这样:
class RouterMap {
public Map getAllRoutes {
Map map = new HashMap
然后在工程代码中将这个map加载到内存中,需要的时候直接get(path)就可以了。
这样,两个模块不用相互有任何直接的依赖,就可以进行转跳,模块与模块之间就相互独立了。
二、APT原理ARouter的使用非常方便,得益于APT。APT的作用是在编译阶段扫描并处理代码中的注解,然后根据注解输出Java文件。
ARouter为了方便实现注解处理器还额外用了两个库。
- 一个是JavaPoet,他提供了调用对象方法的方式生成需要的代码,而不再需要人为的用StringBuilder去拼接代码,再使用IO写入文件。
- 一个是Auto-Service,他提供了简便的方式去注册APT,避免了原本繁琐的注册步骤。
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路径。
RouteProcessorRouteProcessor是对@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 options = processingEnv.getOptions();
if (MapUtils.isNotEmpty(options)) {
moduleName = options.get(KEY_MODULE_NAME);
…………
}
RouteProcessor的process方法是对注解处理的地方,它直接获取了所有Route注解的元素。
Set routeElements = roundEnv.getElementsAnnotatedWith(Route.class);
拿到被标注的元素后就会进入this.parseRoutes(routeElements);方法。这个方法使用JavaPoet生成Java文件。如果不用这个库我们也可以使用StringBuilder去写Java文件的内容。
process回过头来再看RouteProcessor的process方法:
public boolean process(Set annotations, RoundEnvironmentroundEnv) {
if(CollectionUtils.isNotEmpty(annotations)) {
//获取所有Route注解元素
SetrouteElements = roundEnv.getElementsAnnotatedWith(Route.class);
try {
this.parseRoutes(routeElements);
} catch (Exception e) {
logger.error(e);
}
return true;
}
return false;
}
process方法将所有的Route注解元素放进了parseRoutes方法用于生成IRouteGroup和IRouteRoot。这里面使用JavaPoet提供的类,通过方法调用的形式生成代码。
三、路由文件、跳转原理上面利用APT、JavaPoet完成了代码生成的工作,对于一个大型项目,组件数量会很多,可能会有一两百或者更多,把这么多组件都放到这个Map里,显然会对内存造成很大的压力,因此,Arouter采用的方法就是“分组+按需加载”,分组还带来的另一个好处是便于管理,下面我们来看一下实现原理。
解决步骤一:分组首先看如何分组的,Arouter在一层map之外,增加了一层map,我们看WareHouse这个类,里面有两个静态Map:
static Map
关注
打赏
