前言
最近使用了阿里的ARouter框架,现在来讲解一下自己关于ARouter源码的理解
一、ARouter 简介
1. 什么是ARouter
ARouter是由alibaba开源的一个帮助Android App进行组件化路由改造的路由框架。(Github地址)
2. ARouter框架的作用
- 路由:实现页面之间的跳转,包括外部URL跳转到内部页面,module之间页面跳转,可以监听跳转过程同时可以指定拦截器
- 通信:跳转时可以传递参数
- 解耦:跳转不再依赖具体的目标类,各个module之间耦合度降低
二、ARouter原理概述
ARouter功能的实现主要包含三个部分:1.配置和使用 2. 编译期 3. 运行时
1. 配置和使用
关于ARouter的使用方式,其实在GitHub中已经有很明确的介绍,我就不再赘述了。
2. 编译期原理分析
ARouter框架使用时主要用的三个编译期注解为@Route、@Interceptor、@Autowired,在代码的编译期间,利用APT(Annotation Processing Tool)工具生成路由表,对应的注解处理器分别为 RouteProcessor,InterceptorProcessor,AutowiredProcessor,都在arouter-compiler包中。他们都继承自BaseProcessor类,而BaseProcessor继承自AbstractProcessor类,利用Google的@AutoService(Processor.class)注解自动生成服务,当处于编译期间时,编译器会检测继承自AbstractProcessor的子类,调用子类的process()方法,并将包含注解的元素传递进来,然后经过分析后,使用JavaPoet生成java文件。
我们先看一下BaseProcessor类的关键方法,
BaseProcessor.java
//初始化方法,只会执行一次
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
//用于生成.java文件
mFiler = processingEnv.getFiler();
//类型校验
types = processingEnv.getTypeUtils();
//元素校验
elementUtils = processingEnv.getElementUtils();
//类型工具类
typeUtils = new TypeUtils(types, elementUtils);
//封装了日志
logger = new Logger(processingEnv.getMessager());
// Attempt to get user configuration [moduleName]
Map<String, String> options = processingEnv.getOptions();
//读取我们在build.gradle中配置的信息
if (MapUtils.isNotEmpty(options)) {
moduleName = options.get(KEY_MODULE_NAME);
generateDoc = VALUE_ENABLE.equals(options.get(KEY_GENERATE_DOC_NAME));
}
if (StringUtils.isNotEmpty(moduleName)) {
moduleName = moduleName.replaceAll("[^0-9a-zA-Z_]+", "");
logger.info("The user has configuration the module name, it was [" + moduleName + "]");
} else {
//如果没配置会报出异常
logger.error(NO_MODULE_NAME_TIPS);
throw new RuntimeException("ARouter::Compiler >>> No module name, for more information, look at gradle log.");
}
}
@Override
public Set<String> getSupportedOptions() {
//添加Option参数,在build.gradle中配置
return new HashSet<String>() {
{
this.add(KEY_MODULE_NAME);
this.add(KEY_GENERATE_DOC_NAME);
}};
}
BaseProcessor中定义了一些基本的方法,下面我们通过RouteProcessor分析ARouter如何生成路由文件的。
RouteProcessor.java
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
//如果需要生成文档,初始化JavaFile对象,在build.gradle中配置
if (generateDoc) {
try {
docWriter = mFiler.createResource(
StandardLocation.SOURCE_OUTPUT,
PACKAGE_OF_GENERATE_DOCS,
"arouter-map-of-" + moduleName + ".json"
).openWriter();
} catch (IOException e) {
logger.error("Create doc writer failed, because " + e.getMessage());
}
}
......
}
//会自动被编译器调用
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (CollectionUtils.isNotEmpty(annotations)) {
//获取带有Route注解的元素集合
Set<? extends Element> routeElements = roundEnv.getElementsAnnotatedWith(Route.class);
try {
logger.info(">>> Found routes, start... <<<");
//解析路由
this.parseRoutes(routeElements);
} catch (Exception e) {
logger.error(e);
}
return true;
}
return false;
}
//解析数据,组合rootMap、groupMap,生成ARouter$$Group$$xxx,ARouter$$Providers$$xxx,ARouter$$Root$$xxx文件
private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
if (CollectionUtils.isNotEmpty(routeElements)) {
rootMap.clear();
TypeMirror type_Activity = elementUtils.getTypeElement(ACTIVITY).asType();
TypeMirror type_Service = elementUtils.getTypeElement(SERVICE).asType();
TypeMirror fragmentTm = elementUtils.getTypeElement(FRAGMENT).asType();
TypeMirror fragmentTmV4 = elementUtils.getTypeElement(Consts.FRAGMENT_V4).asType();
// Interface of ARouter
TypeElement type_IRouteGroup = elementUtils.getTypeElement(IROUTE_GROUP);
TypeElement type_IProviderGroup = elementUtils.getTypeElement(IPROVIDER_GROUP);
ClassName routeMetaCn = ClassName.get(RouteMeta.class);
ClassName routeTypeCn = ClassName.get(RouteType.class);
//构建 Map<String, Class<? extends IRouteGroup>> 参数类型
ParameterizedTypeName inputMapTypeOfRoot = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ParameterizedTypeName.get(
ClassName.get(Class.class),
WildcardTypeName.subtypeOf(ClassName.get(type_IRouteGroup))
)
);
//构建 Map<String, RouteMeta> 参数类型
ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ClassName.get(RouteMeta.class)
);
//构建com.alibaba.android.arouter.routes包下的
//ARouter$$Group$$xxx,ARouter$$Providers$$xxx,ARouter$$Root$$xxx,三个文件的方法入参
ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build();
ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build(); 、
//构建ARouter$$Root$$xxx的loadInto方法
MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(rootParamSpec);
//for循环解析各种元素,生成不同的RouteMeta
for (Element element : routeElements) {
TypeMirror tm = element.asType();
Route route = element.getAnnotation(Route.class);
RouteMeta routeMeta;
// Activity or Fragment
if (types.isSubtype(tm, type_Activity) || types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {
// Get all fields annotation by @Autowired
Map<String, Integer> paramsType = new HashMap<>();
Map<String, Autowired> injectConfig = new HashMap<>();
injectParamCollector(element, paramsType, injectConfig);
if (types.isSubtype(tm, type_Activity)) {
// Activity
routeMeta = new