转载请注明出处:http://blog.csdn.net/crazy1235/article/details/77126904
前段时间,公司项目在做组件化重构,过程中当然会有很多痛点。
组件化最重要的是根据项目和业务进行分模块,至于模块的粒度就看大家自己来把控了!
这里要说的就是模块之间的数据传输问题
组件化之后,各个模块不相互依赖,那么怎么相互跳转和传递数据呢?
答案就是通过隐式Intent 的方式来跳转和传递数据。
以往的显示Intent 跳转,会存在类直接依赖的问题,这样会导致耦合性非常严重;相比而言,隐式Intent则不需要类之间的直接依赖,但是会出现规则集中式管理,扩展性比较差。
所以在调研期间就发现阿里开源了ARouter–路由框架。
ARouter的好处我这里就不多说,大家可以去看官方文档或者去github上看README。
【https://github.com/alibaba/ARouter】
接下来会分为若干篇blog来分析一下ARouter的源码!
看了ARouter的源码就会发现,它提供了两个SDK,一个是API,一个Compiler。
Compiler SDK 是用于编译器生成相关类文件的。
API SDK 是用在运行期间路由跳转等作用的。
这里先说说Compiler层SDK。
RouteProcessor 路由路径处理器
InterceptorProcessor 拦截器处理器
AutowireProcessor 自动装配处理器
注解处理器的处理流程
(图片转自网络)
实际上,Compiler SDK 只是处根据扫描到的注解生成相应的映射(java)文件。
最后一步通过固定包名加载映射文件是由API SDK来做的。
以官方demo为例来说:
上图所示就是ARouter在编译期间生成的类文件。
红色标注的是 RouteProcessor 生成的类文件
蓝色标注的是 InterceptorProcessor 生成的类文件
橙色标书的是 AutowiredProcessor 生成的类文件
arouter-compiler的目录结构如下:
processor包下面是注解处理器
utils包下面是相关工具类
下面分别说说这三种注解处理器:
用过编译时注解的朋友们都知道,注解处理器需要继承AbstractProcessor ,主要涉及的函数有 init(),process() 这两个。
RouteProcessor
类的继承信息:
@AutoService(Processor.class)
@SupportedOptions(KEY_MODULE_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({ANNOTATION_TYPE_ROUTE, ANNOTATION_TYPE_AUTOWIRED})
public class RouteProcessor extends AbstractProcessor {
init
init()
// 初始化处理器
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
// 文件管理器
mFiler = processingEnv.getFiler(); // Generate class.
// 获取类型处理工具类
types = processingEnv.getTypeUtils(); // Get type utils.
// 获取日志信息工具类
elements = processingEnv.getElementUtils(); // Get class meta.
typeUtils = new TypeUtils(types, elements);
// 封装日志信息类
logger = new Logger(processingEnv.getMessager()); // Package the log utils.
// 获取用户配置的[moduleName]
Map<String, String> options = processingEnv.getOptions();
if (MapUtils.isNotEmpty(options)) {
moduleName = options.get(KEY_MODULE_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 {
// 如果没有在build.gradle中配置moduleName,则会抛出异常。
logger.error("These no module name, at 'build.gradle', like :\n" +
"apt {\n" +
" arguments {\n" +
" moduleName project.getName();\n" +
" }\n" +
"}\n");
throw new RuntimeException("ARouter::Compiler >>> No module name, for more information, look at gradle log.");
}
//
iProvider = elements.getTypeElement(Consts.IPROVIDER).asType();
// RouterProcessor 初始化完毕
logger.info(">>> RouteProcessor init. <<<");
}
// Consts.java
public static final String KEY_MODULE_NAME = "moduleName";
在使用ARouter注解的时候,按照官方文档是需要在每个module里面的build.gradle中配置如下信息:
javaCompileOptions {
annotationProcessorOptions {
arguments = [ moduleName : project.getName() ]
}
}
配置这个属性的目的,就是为了在编译期间生成相关module下的文件和存储文件名称。
process()
一般在process()函数中做的操作如下:
遍历注解的元素
检验元素是否符合要求(过滤元素)
获取输出类参数
生成映射文件(java文件)
错误处理
@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... <<<");
// 调用arseRoute()函数进行处理获取的注解元素集合
this.parseRoutes(routeElements);
} catch (Exception e) {
logger.error(e);
}
// 如果有Route元素的注解,并且处理过程中无异常则返回true
return true;
}
// 否则返回false
return false;
}
parseRoutes()
这个函数的代码有点长,大家耐心看!
// Consts.java
public static final String ACTIVITY = "android.app.Activity";
public static final String FRAGMENT = "android.app.Fragment";
public static final String FRAGMENT_V4 = "android.support.v4.app.Fragment";
public static final String SERVICE = "android.app.Service";
private static final String FACADE_PACKAGE = "com.alibaba.android.arouter.facade";
private static final String TEMPLATE_PACKAGE = ".template";
public static final String IROUTE_GROUP = FACADE_PACKAGE + TEMPLATE_PACKAGE + ".IRouteGroup";
public static final String IPROVIDER_GROUP = FACADE_PACKAGE + TEMPLATE_PACKAGE + ".IProviderGroup";
private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
if (CollectionUtils.isNotEmpty(routeElements)) {
// ...
rootMap.clear();
// 获取ACTIVITY, SERVICE, FRAGMENT, FRAGMENT_V4 这四种 类型镜像
TypeMirror type_Activity = elements.getTypeElement(ACTIVITY).asType();
TypeMirror type_Service = elements.getTypeElement(SERVICE).asType();
TypeMirror fragmentTm = elements.getTypeElement(FRAGMENT).asType();
TypeMirror fragmentTmV4 = elements.getTypeElement(Consts.FRAGMENT_V4).asType();
// ARouter的接口
TypeElement type_IRouteGroup = elements.getTypeElement(IROUTE_GROUP);
TypeElement type_IProviderGroup = elements.getTypeElement(IPROVIDER_GROUP);
//
// 下面就是遍历获取的注解信息,通过javapoet来生成类文件了
ClassName routeMetaCn = ClassName.get(RouteMeta.class);
ClassName routeTypeCn = ClassName.get(RouteType.class);
/*
ParameterizedTypeName用来创建类型对象,例如下面
```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))
)
);
/*
RouteMeta封装了路由相关的信息
```Map<String, RouteMeta>```
*/
ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ClassName.get(RouteMeta.class)
);
/*
创建输入参数
*/
// 1。 生成的参数:Map<String, Class<? extends IRouteGroup>> routes
ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build(); // 第一个参数表示参数类型,第二个函数表示参数名称
// 2。 Map<String, RouteMeta> atlas
ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
// 3。 Map<String, Rou