已在多个项目中使用ARoute实现组件化间的路由通信,但是一直没有很完整的阅读过ARoute框架的源码。刚好这段时间想拜读一些知名框架的源码,那就从熟悉的ARoute开始吧!
若有错误的地方欢迎大家指正。
本篇博客就从ARoute的初始化流程开始,调用的初始化代码如下:
ARouter.init(getApplication());
ARouter.init(getApplication())方法实际调用的是_ARouter类里面的init(),ARoute中的代码如下:
/**
* Init, it must be call before used router.
*/
public static void init(Application application) {
if (!hasInit) {
logger = _ARouter.logger;
_ARouter.logger.info(Consts.TAG, "ARouter init start.");
hasInit = _ARouter.init(application);
、、、(暂时省略无关代码)
}
}
_ARoute中的init()代码如下:
protected static synchronized boolean init(Application application) {
mContext = application;
LogisticsCenter.init(mContext, executor);
logger.info(Consts.TAG, "ARouter init success!");
hasInit = true;
mHandler = new Handler(Looper.getMainLooper());
return true;
}
关键代码在于“LogisticsCenter.init(mContext, executor);”,下面就来分析这句代码里面都做了什么:
/**
* LogisticsCenter init, load all metas in memory. Demand initialization
*/
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
```
try {
```
Set<String> routerMap;
// It will rebuild router map every times when debuggable.
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
// These class was generated by arouter-compiler.
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();
}
// Save new version name when router map update finishes.
PackageUtils.updateVersion(context);
} else {
logger.info(TAG, "Load router map from cache.");
//Todo 遍历dex 根据包名获取所有的class文件,
routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY,
Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
}
```
//todo 保存路由地址与类的对应关系
for (String className : routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR +
SUFFIX_ROOT)) {
// This one of root elements, load root.
((IRouteRoot) (Class.forName(className).getConstructor().newInstance()))
.loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME +
SEPARATOR + SUFFIX_INTERCEPTORS)) {
// Load interceptorMeta
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance()))
.loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME +
SEPARATOR + SUFFIX_PROVIDERS)) {
// Load providerIndex
((IProviderGroup) (Class.forName(className).getConstructor().newInstance()))
.loadInto(Warehouse.providersIndex);
}
}
}
```
} catch (Exception e) {
throw new HandlerException(TAG + "ARouter init logistics center exception!
[" + e.getMessage() + "]");
}
}
上面代码隐藏了部分不重要的代码。
这段代码主要功能就是遍历dex文件,根据包名获取所有的类,然后判断类名中开头如果是:
“com.alibaba.android.arouter.routes.ARouter$$Root、
com.alibaba.android.arouter.routes.ARouter$$Interceptors、
com.alibaba.android.arouter.routes.ARouter$$Providers”
这三个类型,则构造出类并调用类中的loadInit()方法,那么接下来就看一下这三个类中的loadInit()具体做了什么:
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER.
*/
public class ARouter$$Group$$arouter implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/arouter/service/autowired", RouteMeta.build(RouteType.PROVIDER,
AutowiredServiceImpl.class, "/arouter/service/autowired", "arouter", null,
-1, -2147483648));
atlas.put("/arouter/service/interceptor", RouteMeta.build(RouteType.PROVIDER,
InterceptorServiceImpl.class, "/arouter/service/interceptor", "arouter",
null, -1, -2147483648));
}
}
三个类所在的位置如下图所示:
三个类都是相似的,接下来主要分析“ARouter$$Group/$/$arouter”。由其源码可知,这是ARoute自动生成的三个类,在loadInit()中的功能就是把各个URL对应的信息封装在RouteMeta对象中,然后存储到atlas,从上一步的源码可知这个传进来的atlas是Warehouse类中的静态Map类型变量,由此可知所有class与路由地址的映射关系都存储在这个Warehouse中。源码如下:
class Warehouse {
// Cache route and metas
static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
static Map<String, RouteMeta> routes = new HashMap<>();
// Cache provider
static Map<Class, IProvider> providers = new HashMap<>();
static Map<String, RouteMeta> providersIndex = new HashMap<>();
// Cache interceptor
static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new
UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
static List<IInterceptor> interceptors = new ArrayList<>();
static void clear() {
routes.clear();
groupsIndex.clear();
providers.clear();
providersIndex.clear();
interceptors.clear();
interceptorsIndex.clear();
}
}
到此_ARouter.Init();就执行完了,再看回ARoute.init()方法中还做了什么:
public static void init(Application application) {
if (!hasInit) {
```
hasInit = _ARouter.init(application);
if (hasInit) {
_ARouter.afterInit();
}
_ARouter.logger.info(Consts.TAG, "ARouter init over.");
}
}
从源码中可知,init完成后调用了_ARoute.afterInte()去创建了路由地址为“/arouter/service/interceptor”的拦截器,源码如下:
static void afterInit() {
// Trigger interceptor init, use byName.
interceptorService = (InterceptorService)
ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
到此,ARoute的初始化流程源码分析暂时告一段落,下面贴上对应的时序图:
分析完ARoute留下了两个疑问点:
1、ARoute是如何自动生成“ARouter/$/$Group$$xxx”这些文件的?
2、创建拦截器的代码其工作原理是什么:
(InterceptorService)ARouter.getInstance()
.build("/arouter/service/interceptor").navigation();
带着这两个问题,继续我们的ARoute源码阅读之旅......