// …
} catch (Exception e) {
throw new HandlerException(TAG + “ARouter init logistics center exception! [” + e.getMessage() + “]”);
}
}
这里主要有如下几步:
-
获取
com.alibaba.android.arouter.routes
下存储 ClassName 的集合routerMap
。 -
若为 debug 模式或之前没有解析过
routerMap
,则通过ClassUtils.getFileNameByPackageName
方法对指定 package 下的所有 ClassName 进行解析并存入 SP。 -
若并非 debug 模式,并且之前已经解析过,则直接从 SP 中取出。(debug 每次都需要更新,因为类会随着代码的修改而变动)
-
遍历
routerMap
中的 ClassName。 -
如果是
RouteRoot
,则加载类构建对象后通过loadInto
加载进Warehouse.groupsIndex
。 -
如果是
InterceptorGroup
,则加载类构建对象后通过loadInto
加载进Warehouse.interceptorsIndex
。 -
如果是
ProviderGroup
,则加载类构建对象后通过loadInto
加载进Warehouse.providersIndex
。
解析 ClassName
我们先看看 ClassUtils.getFileNameByPackageName
是如何对指定 package 下的 ClassName 集合进行解析的:
public static Set getFileNameByPackageName(Context context, final String packageName) {
final Set classNames = new HashSet<>();
// 通过 getSourcePaths 方法获取 dex 文件 path 集合
List paths = getSourcePaths(context);
// 通过 CountDownLatch 对 path 的遍历处理进行控制
final CountDownLatch parserCtl = new CountDownLatch(paths.size());
// 遍历 path,通过 DefaultPoolExecutor 并发对 path 进行处理
for (final String path : paths) {
DefaultPoolExecutor.getInstance().execute(new Runnable() {
@Override
public void run() {
// 加载 path 对应的 dex 文件
DexFile dexfile = null;
try {
if (path.endsWith(EXTRACTED_SUFFIX)) {
// zip 结尾通过 DexFile.loadDex 进行加载
dexfile = DexFile.loadDex(path, path + “.tmp”, 0);
} else {
// 否则通过 new DexFile 加载
dexfile = new DexFile(path);
}
// 遍历 dex 中的 Entry
Enumeration dexEntries = dexfile.entries();
while (dexEntries.hasMoreElements()) {
// 如果是对应的 package 下的类,则添加其 className
String className = dexEntries.nextElement();
if (className.startsWith(packageName)) {
classNames.add(className);
}
}
} catch (Throwable ignore) {
Log.e(“ARouter”, “Scan map file in dex files made error.”, ignore);
} finally {
if (null != dexfile) {
try {
dexfile.close();
} catch (Throwable ignore) {
}
}
parserCtl.countDown();
}
}
});
}
// 所有 path 处理完成后,继续向下走
parserCtl.await();
Log.d(Consts.TAG, “Filter " + classNames.size() + " classes by packageName <” + packageName + “>”);
return classNames;
}
这里的步骤比较简单,主要是如下的步骤:
-
通过
getSourcePaths
方法获取 dex 文件的 path 集合。 -
创建了一个
CountDownLatch
控制 dex 文件的并行处理,以加快速度。 -
遍历 path 列表,通过
DefaultPoolExecutor
对 path 并行处理。 -
加载 path 对应的 dex 文件,并对其中的 Entry 进行遍历,若发现了对应 package 下的 ClassName,将其加入结果集合。
-
所有 dex 处理完成后,返回结果。
关于 getSourcePaths
如何获取到的 dex 集合这里就不纠结了,因为我们的关注点不在这里。
初始化 Warehouse
Warehouse
实际上就是仓库的意思,它存放了 ARouter
自动生成的类(RouteRoot
、InterceptorGroup
、ProviderGroup
)的信息。
我们先看看 Warehouse
类究竟是怎样的:
class Warehouse {
// 保存 RouteGroup 对应的 class 以及 RouteMeta
static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
static Map<String, RouteMeta> routes = new HashMap<>();
// 保存 Provider 以及 RouteMeta
static Map<Class, IProvider> providers = new HashMap<>();
static Map<String, RouteMeta> providersIndex = new HashMap<>();
// 保存 Interceptor 对应的 class 以及 Inteceptor
static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>(“More than one interceptors use same priority [%s]”);
static List interceptors = new ArrayList<>();
static void clear() {
routes.clear(