@Route
在组件化,模块化过程中,经常会遇到不同的模块之间进行页面跳转,通信等;
ARouter
提供了@Route
注解来简化这一过程。
定义
先来看看 @Route
的定义。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Route {
// 路径
String path();
// 组名,如果不指定,会取路径上的第一层级作为组名
String group() default "";
// 生成doc 用的
String name() default "";
int extras() default Integer.MIN_VALUE;
// 优先级,值越小,优先级越高
int priority() default -1;
}
-
path()
用来定义路径,必须以 / 开头; -
group()
用来划分组,如果不指定,则默认取path()
的第一级; -
name()
是生成文档时使用的; -
extras()
配置一些额外的信息; -
priority()
定义优先级;
下面我们通过几个简单的例子,来看看 @Route
在实际开发中的作用。
路由
@Route
可以简化跨模块之间的路由。
举个栗子,在模块 A 中有 AActivity
,模块 B 中有 BActivity
,这时 AActivity
想要跳转 BActivity
,是不能直接通过显式的 Intent
进行跳转的,当然我们也可以通过隐示的 Intent
进行跳转,但是一个项目有成百上千个页面,这样做无疑增加了维护的成本。
这个时候我们可以通过 @Route
给 BActivity
增加一些配置。
@Route(path = "/b/activity1")
public class BActivity extends AppCompatActivity {
}
这样一来,AActivity
跳转 BActivity
只需要通过 ARouter
暴露的 API
就可以轻松实现跨模块跳转了。
ARouter.getInstance().build("/b/activity1")
.withString("xxx", "xxx")
.withInt("xxx", xxx)
.withSerializable("xxx", xxx)
.withParcelable("xxx", xxx)
.withObject("xxx", xxx)
.navigation();
通信
@Route
可以简化跨模块之间的通信。
模块与模块之间可能不仅仅只是简单的页面路由等,或多或少都会存在一些数据访问等操作。
举个栗子,模块 A 需要访问 模块 B 的一些数据,我们可以通过 @Route
和 IProvider
轻松简化这一过程。
public interface IBService extends IProvider {
void hello();
}
@Route(path = "/b/service")
public class BServiceImpl implements IBService {
@Override
public void init(Context context) {
}
@Override
public void hello() {
Log.d("ppdai", "hello");
}
}
定义模块 B 想要暴露给其他模块的服务 IBService
,并让其继承 IProvider
,然后在模块 B 中定义实现 BServiceImpl
,通过 @Route
注解注册路由信息,这个时候模块 A 就可以通过相同的 API
访问 B 模块的东西。
BServiceImpl bService = (BServiceImpl) ARouter.getInstance().build("/b/service").navigation();
bService.hello();
源码分析
接下来具体分析一下源码,来看看 ARouter
是如何实现的。
首先,我们先来看看初始化过程,通常我们会在 Application
中对 ARouter
进行初始化操作。
ARouter.init();
那么,初始化它究竟初始化了什么呢?我们先来看看 init()
。
public static void init(Application application) {
if (!hasInit) {
logger = _ARouter.logger;
_ARouter.logger.info(Consts.TAG, "ARouter init start.");
// 调用 _ARouter.init()
hasInit = _ARouter.init(application);
if (hasInit) {
_ARouter.afterInit();
}
_ARouter.logger.info(Consts.TAG, "ARouter init over.");
}
}
这里实际上是调用了 _ARouter.init()
。
protected static synchronized boolean init(Application application) {
mContext = application;
// 调用 LogisticsCenter.init()
LogisticsCenter.init(mContext, executor);
logger.info(Consts.TAG, "ARouter init success!");
hasInit = true;
mHandler = new Handler(Looper.getMainLooper());
return true;
}
然后在 _ARouter.init()
中调用了 LogisticsCenter.init()
。
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
try {
loadRouterMap();
if (registerByPlugin) {
logger.info(TAG, "Load router map by arouter-auto-register plugin.");
} else {
Set<String> routerMap;
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
// 1. 调用 getFileNameByPackageName() 加载 路由配置信息
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
if (!routerMap.isEmpty()) {
context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
}
PackageUtils.updateVersion(context); // Save new version name when router map update finishes.
} else {
routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
}
// 2. 遍历加载路由之后存放的类
for (String className : routerMap) {
// 2.1 如果是 com.alibaba.android.arouter.routes.ARouter$$Root ...
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
// 2.1.1 调用其 loadInfo() ,并将信息缓存到 Warehouse 里面
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
// 2.2 如果是 com.alibaba.android.arouter.routes.ARouter$$Interceptors .. 调用其 loadInfo() 并将信息存放到 Warehouse 里面
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
// 2.3 如果是 com.alibaba.android.arouter.routes.ARouter$$Providers.. 调用其 loadInfo() 并将信息存放到 WareHouse 里面
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
}
} catch (Exception e) {
throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
}
}
这个方法主要做了两件事情
- 调用
ClassUtils.getFileNameByPackageName()
查找所有在编译期通过注解处理器生成的类,并将其存放到routerMap
中,这里的getFileNameByPackageName()
就不具体看了,感兴趣的童鞋可以自行研究一下,主要是找dex
里面com.alibaba.android.arouter.routes
包下面的类,这些类都是通过APT
在编译时期生成的,后面我们分析RouteProcessor
的时候就明白了; - 通过
for
循环遍历routerMap
分别调用其loadInfo()
将路由配置信息存放到Warehouse
中;
所以,在初始化的过程中,ARouter
就将所有的路由信息都存放到了 Warehouse
中。
接下来,我们再来看看分析一下使用过程,这里我们以 Activity
的路由为例。
ARouter.getInstance().build("/b/activity1").navigation(context)
这里 build()
的时候会构建一个 Postcard
对象,然后调用其 navigation()
,我们来看看 navigation()
做了什么。
public Object navigation(Context context) {
return navigation(context, null);
}
public Object navigation(Context context, NavigationCallback callback) {
return ARouter.getInstance().navigation(context, this, -1, callback);
}
public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {
return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);
}
从调用链可以看到,它最终调用到了 _ARouter
的 navigation()
,我们接着往下看。
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
// Pretreatment failed, navigation canceled.
return null;
}
try {
// 1. 找到 path 对应的 路由信息
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
logger.warning(Consts.TAG, ex.getMessage());
if (null != callback) {
callback.onLost(postcard);
} else {
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
return null;
}
if (null != callback) {
callback.onFound(postcard);
}
if (!postcard.isGreenChannel()) {
// 通过 isGreenChannel() 判断是否需要走拦截器逻辑
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
/**
* Continue process
*
* @param postcard route meta
*/
@Override
public void onContinue(Postcard postcard) {
_navigation(context, postcard, requestCode, callback);
}
/**
* Interrupt process, pipeline will be destory when this method called.
*
* @param exception Reson of interrupt.
*/
@Override
public void onInterrupt(Throwable exception) {
if (null != callback) {
callback.onInterrupt(postcard);
}
logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());
}
});
} else {
// 最终会走到这里
return _navigation(context, postcard, requestCode, callback);
}
return null;
}
这里先通过 LogisticsCenter.completion()
找到 path
对应的路由信息,然后通过 isGreenChannel()
决定是否走到拦截器里面,拦截器逻辑不在本文分析之内,后面会单独写一篇文章分析拦截器的原理。我们接着看 _navigation()
。
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = null == context ? mContext : context;
switch (postcard.getType()) {
case ACTIVITY:
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());
int flags = postcard.getFlags();
if (-1 != flags) {
intent.setFlags(flags);
} else if (!(currentContext instanceof Activity)) {
// 使用非 Activity 的 context 启动 Activity,需要添加 FLAG_ACTIVITY_NEW_TASK 标记
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
String action = postcard.getAction();
if (!TextUtils.isEmpty(action)) {
intent.setAction(action);
}
runInMainThread(new Runnable() {
@Override
public void run() {
// 启动 Activity
startActivity(requestCode, currentContext, intent, postcard, callback);
}
});
break;
// ...
default:
return null;
}
return null;
}
可以看到 _navigation()
中对 Intent
进行了组装,然后调用了 startActivity()
,这个方法我们就不分析了,就是通过 context
去启动对应的 Activity
了。
RouteProcessor
没错,
RouteProcessor
就是@Route
注解的处理器了,如此强大的功能, 我们还真得好好研究一下它。
我们先看看 init()
方法做了什么
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
// 1. 判断是否需要生成路由的 json 文件
if (generateDoc) {
try {
// 如果使用的是 kapt ,这个文件是在 build/generated/source/kapt/[buildVariant]/com.alibaba.android.arouter.docs
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());
}
}
// 2. 获取 IProvider 的 TypeMirror
iProvider = elementUtils.getTypeElement(Consts.IPROVIDER).asType();
}
init()
方法做的事情很简单;
- 使用
generateDoc
字段判断是否需要生成arouter-map-of-modulename.json
文件,并生成对应的Writer
; - 获取到
IProvider
的TypeMirror
;
这里的 generateDoc
我们看一下父类 BaseProcessor
的 init()
方法,就知道是个什么情况了。
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
// ...
Map<String, String> options = processingEnv.getOptions();
if (MapUtils.isNotEmpty(options)) {
moduleName = options.get(KEY_MODULE_NAME);
// 获取在 build.gradle 里面配置的参数 AROUTER_GENERATE_DOC ,判断是否是 enable
generateDoc = VALUE_ENABLE.equals(options.get(KEY_GENERATE_DOC_NAME));
}
// ...
}
也就是说,如果我们需要生成路由的 json
文件,需要在 build.gradle
中新增如下配置。
kapt {
arguments {
// ...
// 配置需要生成路由的 json 文件
arg("AROUTER_GENERATE_DOC", "enable")
}
}
然后编译项目,就可以看到生成的 json
文件了。
{
"logistic":[
{
"group":"logistic",
"path":"/logistic/detail",
"className":"com.mockuai.module.order.logistic.detail.LogisticDetailActivity",
"type":"activity",
"mark":-2147483648
},
{
"group":"logistic",
"path":"/logistic/list",
"className":"com.mockuai.module.order.logistic.list.LogisticListActivity",
"type":"activity",
"mark":-2147483648
}
],
"order":[
{
"group":"order",
"path":"/order/distribution/detail",
"className":"com.mockuai.module.order.distribution.detail.DistributionOrderDetailActivity",
"type":"activity",
"mark":-2147483648
},
{
"group":"order",
"path":"/order/sample/list",
"className":"com.mockuai.module.order.sample.list.SampleOrderListActivity",
"type":"activity",
"mark":-2147483648
}
]
}
分析完 init()
方法之后,我们再来分析 process()
方法。
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (CollectionUtils.isNotEmpty(annotations)) {
// 1. 获取到所有的@Route注解处理的 Element
Set<? extends Element> routeElements = roundEnv.getElementsAnnotatedWith(Route.class);
try {
// 2. 调用 parseRoutes() 进行处理
this.parseRoutes(routeElements);
} catch (Exception e) {
logger.error(e);
}
return true;
}
return false;
}
从 process()
方法可以看到,主要起作用的是 parseRoutes()
,这个方法大概几百行,我们还是一部分一部分来分析。
// 获取 android.app.Activity 的 TypeMirror
TypeMirror type_Activity = elementUtils.getTypeElement(ACTIVITY).asType();
// 获取 android.app.Service 的 TypeMirror
TypeMirror type_Service = elementUtils.getTypeElement(SERVICE).asType();
// 获取 android.app.Fragment 的 TypeMirror
TypeMirror fragmentTm = elementUtils.getTypeElement(FRAGMENT).asType();
// 获取 android.support.v4.app.Fragment 的 TypeMirror
TypeMirror fragmentTmV4 = elementUtils.getTypeElement(Consts.FRAGMENT_V4).asType();
// 获取 com.alibaba.android.arouter.facade.template.IRouteGroup 的 TypeElement
TypeElement type_IRouteGroup = elementUtils.getTypeElement(IROUTE_GROUP);
// 获取 com.alibaba.android.arouter.facade.template.IProvider 的 TypeElement
TypeElement type_IProviderGroup = elementUtils.getTypeElement(IPROVIDER_GROUP);
// 获取 RouteMeta 的 ClassName
ClassName routeMetaCn = ClassName.get(RouteMeta.class);
// 获取 RouteType 的 ClassName
ClassName routeTypeCn = ClassName.get(RouteType.class);
这一部分的代码只是做了一些数据获取操作,后面会用到这些数据,我们继续向下分析。
// 构建参数类型 Map<String, RouteMeta>
ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ClassName.get(RouteMeta.class)
);
// 构建参数 Map<String, Class<? extends IRouteGroup> routes
ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot,
"routes").build();
// 构建参数 Map<String ,RouteMeta> atlas
ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup,
"atlas").build();
// 构建参数 Map<String, RouteMeta> providers
ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup,
"providers").build(); // Ps. its param type same as groupParamSpec!
/**
* 构建方法
* @Overrid
* public void loadInfo(Map<String, Class<? extends IRouteGroup> routes) {
*
* }
*/
MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(
METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(rootParamSpec);
这一部分代码用 javapoet
定义了一些需要生成的文件里面的方法和参数,为生成最终的文件做准备。我们继续向下分析。
for (Element element : routeElements) {
// 1. 获取 TypeElement 元素的 TypeMirror 实例,用于判断是Activity,Fragment,Service,IProvider等
TypeMirror tm = element.asType();
// 2. 获取 TypeElement 上修饰的 @Route 实例
Route route = element.getAnnotation(Route.class);
RouteMeta routeMeta;
// 3. 判断 TypeElement 的类型;
if (types.isSubtype(tm, type_Activity)) {
// 3.1 如果是 Activity ,则构建 Activity 对应的 RouteMeta ,RouteMeta 是存放路由信息的类。
Map<String, Integer> paramsType = new HashMap<>();
Map<String, Autowired> injectConfig = new HashMap<>();
for (Element field : element.getEnclosedElements()) {
// 遍历当前类的所有元素,找到类型为 FIELD 的 且有 @Autowired注解修改的,并且属性不是IProvider子类,然后存放到对应的 Map 中;
if (field.getKind().isField() && field.getAnnotation(Autowired.class)
!= null && !types.isSubtype(field.asType(), iProvider)) {
// 获取属性上的 @Autowired 实例
Autowired paramConfig = field.getAnnotation(Autowired.class);
// 获取注入的key名称
String injectName = StringUtils.isEmpty(paramConfig.name())
? field.getSimpleName().toString() : paramConfig.name();
// 存放到 paramsType 里面
paramsType.put(injectName, typeUtils.typeExchange(field));
// 存放到 injectConfig 里面
injectConfig.put(injectName, paramConfig);
}
}
// 创建当前 Activity 的 RouteMeta(存放路由信息的类)
routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
routeMeta.setInjectConfig(injectConfig);
} else if (types.isSubtype(tm, iProvider)) {
// 3.2 如果是 IProvider ,则创建 IProvider 的 RouteMeta
routeMeta = new RouteMeta(route, element, RouteType.PROVIDER, null);
} else if (types.isSubtype(tm, type_Service)) {
// 3.3 如果是 Service , 则创建 Service 的 RouteMeta
routeMeta = new RouteMeta(route, element, RouteType.parse(SERVICE), null);
} else if (types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {
// 3.4 如果是 Fragment ,则创建 Fragment 的 RouteMeta
routeMeta = new RouteMeta(route, element, RouteType.parse(FRAGMENT), null);
} else {
// 3.5 可以看到,@Route 只支持 Activity,IProvider,Service,Fragment
throw new RuntimeException(
"ARouter::Compiler >>> Found unsupported class type, type = ["
+ types.toString() + "].");
}
// 4. 调用 categories() 对 RouteMeta 进行分类处理。
categories(routeMeta);
}
这里通过 for
语句对所有 @Route
修饰的类的 TypeElement
元素进行遍历,然后根据其具体的类型,生成对应的 RouteMeta
对象,存放路由信息。
- 获取
TypeElement
元素的TypeMirror
实例,用于判断是否是Activity
,Fragment
,Service
,IProvider
; - 获取
TypeElement
上修饰的@Route
实例; - 判断当前类的具体类型,并生成对应的
RouteMeta
存放路由信息; - 调用
categories()
对RouteMeta
进行分类。
我们再看看 categories()
方法做了什么。
private void categories(RouteMeta routeMeta) {
// 1. 校验 routeMeta 里面存放的路径是否是正确的
if (routeVerify(routeMeta)) {
Set<RouteMeta> routeMetas = groupMap.get(routeMeta.getGroup());
// 2. 根据 group 进行分组存放到 groupMap 里面
if (CollectionUtils.isEmpty(routeMetas)) {
Set<RouteMeta> routeMetaSet = new TreeSet<>(new Comparator<RouteMeta>() {
@Override
public int compare(RouteMeta r1, RouteMeta r2) {
try {
return r1.getPath().compareTo(r2.getPath());
} catch (NullPointerException npe) {
logger.error(npe.getMessage());
return 0;
}
}
});
routeMetaSet.add(routeMeta);
groupMap.put(routeMeta.getGroup(), routeMetaSet);
} else {
routeMetas.add(routeMeta);
}
}
}
categories()
方法的逻辑很简单,对路由信息进行分类。
- 通过
routeVerify()
对RouteMeta
进行校验; - 按照
group
进行分类,存放到groupMap
中。
看完 categories()
,我们接着往下看 parseRoutes()
。
/**
* @Overrid
* public void loadInfo(Map<String, RouteMeta> providers) {
*
* }
*/
MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(
METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(providerParamSpec);
这里也是使用 javapoet
定义了 loadInfo()
方法。
// 这里对 categories() 方法分类后的 groupMap 进行遍历
for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) {
String groupName = entry.getKey();
/**
* @Overrid
* public void loadInfo(Map<String, RouteMeta>> atlas) {
*
* }
*/
Spec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(
METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(groupParamSpec);
List<RouteDoc> routeDocList = new ArrayList<>();
Set<RouteMeta> groupData = entry.getValue();
// 遍历当前 group 下面所有的 RouteMeta
for (RouteMeta routeMeta : groupData) {
RouteDoc routeDoc = extractDocInfo(routeMeta);
ClassName className = ClassName.get((TypeElement) routeMeta.getRawType());
switch (routeMeta.getType()) {
case PROVIDER:
// 获取实现的接口
List<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces();
// 遍历接口
for (TypeMirror tm : interfaces) {
routeDoc.addPrototype(tm.toString());
if (types.isSameType(tm, iProvider)) {
loadIntoMethodOfProviderBuilder.addStatement(
"providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
(routeMeta.getRawType()).toString(),
routeMetaCn,
routeTypeCn,
className,
routeMeta.getPath(),
routeMeta.getGroup());
} else if (types.isSubtype(tm, iProvider)) {
loadIntoMethodOfProviderBuilder.addStatement(
"providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
tm.toString(),
routeMetaCn,
routeTypeCn,
className,
routeMeta.getPath(),
routeMeta.getGroup());
}
}
break;
default:
break;
}
StringBuilder mapBodyBuilder = new StringBuilder();
Map<String, Integer> paramsType = routeMeta.getParamsType();
Map<String, Autowired> injectConfigs = routeMeta.getInjectConfig();
if (MapUtils.isNotEmpty(paramsType)) {
List<RouteDoc.Param> paramList = new ArrayList<>();
// 对非IProvider且被@Autowired修饰的域进行处理
for (Map.Entry<String, Integer> types : paramsType.entrySet()) {
mapBodyBuilder.append("put(\"").append(types.getKey()).append("\", ").append(types.getValue()).append("); ");
RouteDoc.Param param = new RouteDoc.Param();
Autowired injectConfig = injectConfigs.get(types.getKey());
param.setKey(types.getKey());
param.setType(TypeKind.values()[types.getValue()].name().toLowerCase());
param.setDescription(injectConfig.desc());
param.setRequired(injectConfig.required());
paramList.add(param);
}
routeDoc.setParams(paramList);
}
String mapBody = mapBodyBuilder.toString();
// 添加路由信息
loadIntoMethodOfGroupBuilder.addStatement(
"atlas.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, " + (StringUtils.isEmpty(mapBody) ? null : ("new java.util.HashMap<String, Integer>(){{" + mapBodyBuilder.toString() + "}}")) + ", " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
routeMeta.getPath(),
routeMetaCn,
routeTypeCn,
className,
routeMeta.getPath().toLowerCase(),
routeMeta.getGroup().toLowerCase());
routeDoc.setClassName(className.toString());
routeDocList.add(routeDoc);
}
// 生成 ARouter$$Group$$groupName 文件
String groupFileName = NAME_OF_GROUP + groupName;
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(groupFileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(type_IRouteGroup))
.addModifiers(PUBLIC)
.addMethod(loadIntoMethodOfGroupBuilder.build())
.build()
).build().writeTo(mFiler);
rootMap.put(groupName, groupFileName);
docSource.put(groupName, routeDocList);
}
这里对 categories()
处理后的 groupMap
进行遍历,然后生成对应的 IRouteGroup
文件 ARouter$$Group$$grouName
。我们继续往下看。
if (MapUtils.isNotEmpty(rootMap)) {
// 给 IRouteRoot 的 loadInfo() 添加数据
for (Map.Entry<String, String> entry : rootMap.entrySet()) {
loadIntoMethodOfRootBuilder.addStatement("routes.put($S, $T.class)", entry.getKey(), ClassName.get(PACKAGE_OF_GENERATE_FILE, entry.getValue()));
}
}
// 生成doc文件
if (generateDoc) {
docWriter.append(JSON.toJSONString(docSource, SerializerFeature.PrettyFormat));
docWriter.flush();
docWriter.close();
}
// 生成 ARouter$$Providers$$moduleName,存放所有注册的IProvider 信息
String providerMapFileName = NAME_OF_PROVIDER + SEPARATOR + moduleName;
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(providerMapFileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(type_IProviderGroup))
.addModifiers(PUBLIC)
.addMethod(loadIntoMethodOfProviderBuilder.build())
.build()
).build().writeTo(mFiler);
// 生成 ARouter$$Root$$moduleName ,存放 groupName 和 IRouteGroup 的映射关系
String rootFileName = NAME_OF_ROOT + SEPARATOR + moduleName;
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(rootFileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(elementUtils.getTypeElement(ITROUTE_ROOT)))
.addModifiers(PUBLIC)
.addMethod(loadIntoMethodOfRootBuilder.build())
.build()
).build().writeTo(mFiler);
这段代码就比较简单了,使用 javapoet
生成了三个文件。
到此,对 RouteProcessor
的源码我们就分析完了。总结来说,经过 RouteProcessor
的处理,会生成如下几类文件。
-
ARouter$$Group$$groupName
,实现了IRouteGroup
,用来存放当前groupName
下所有的路由信息; -
ARouter$$Root$$moduleName
,实现了IRouteRoot
,用来存放当前模块下,groupName
与IRouteGroup
的映射关系; -
ARouter$$Providers$$moduleName
,实现了IProviderGroup
,用来存放当前模块下所有注册的IProvider
的映射关系; - 根据
generateDoc
,决定是否生成arouter-map-of-modulename.json
说明文档;
至此,RouteProcessor
的源码就分析完了。
图解
通过上面的分析,我们大致可以画出 @Route
的基本原理。