我们找到Arouter的入口,也就是初始化的地方:
if (isDebug()) { // 这两行必须写在init之前,否则这些配置在init过程中将无效
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化
我们直接看ARouter.init方法
/**
* 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);
if (hasInit) {
_ARouter.afterInit();
}
_ARouter.logger.info(Consts.TAG, "ARouter init over.");
}
}
接着我们进入实现类看下: 继续看 _ARouter.java 实现
protected static synchronized boolean init(Application application) {
mContext = application;
LogisticsCenter.init(mContext, executor); // 实际初始化的地方
logger.info(Consts.TAG, "ARouter init success!");
hasInit = true;
return true;
}
我们只关注重点,LogisticsCenter.init(mContext, executor);
,executor是一个线程池。
主要实现都在 LogisticsCenter.init 方法 中, 继续查看
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
mContext = context;
executor = tpe;
...
Set<String> routerMap;//生成类的类名集合
// 如果是debug模式或者是新版本,从apt生成的包中加载类
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
// ClassUtils.getFileNameByPackageName 就是根据报名查找对应报名下的类, 就不贴代码了..
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
if (!routerMap.isEmpty()) {//加入sp缓存
context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
}
PackageUtils.updateVersion(context); //更新版本
} else {//否则从缓存读取类名
routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
}
//判断类型,使用反射实例化对象,并调用方法 // 遍历获取到的 class
for (String className : routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
`ROUTE_ROOT_PAKCAGE`是一个常量:
```java
public static final String ROUTE_ROOT_PAKCAGE = "com.alibaba.android.arouter.routes";
而ClassUtils.getFileNameByPackageName
方法做的就是找到app的dex,然后遍历出其中的属于com.alibaba.android.arouter.routes
包下的所有类名,打包成集合返回。可以想象遍历整个dex查找指定类名的工作量有多大,怎么办呢?
就需要arouter-gradle-plugin ASM插桩 来解决这个非常耗费性能问题
可以看到初始化就是查找com.alibaba.android.arouter.routes包下的类, 获取实例并强制转化成IRouteRoot,
IInterceptorGroup, IProviderGroup, 然后调用 loadInto 方法.
通过 demo 的代码查找能看到有
com.alibaba.android.arouter.routes.ARouter$$Root$$app
这样的类
// ARouter$$Root$$app.java
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Root$$app implements IRouteRoot {
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
// 以分组做为 key, 缓存到 routes.
// routes 是指向 Warehouse.groupsIndex 的引用
routes.put("service", ARouter$$Group$$service.class);
routes.put("test", ARouter$$Group$$test.class);
}
}
可以看到这是在编译期通过分析注解生成的代码.ARouter$$Group$$service.class
也是生成.
// ARouter$$Group$$service.java
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Group$$service implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/service/hello", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/service/hello", "service", null, -1, -2147483648));
...
}
}
到这里可以看到demo代码里定义的HelloServiceImpl.java 等出现了. 其实 ARouter
就是通过分析注解在编译期自动生成了一些关联代码. 另外的 Interceptors, Providers 逻辑上类似.
Interceptors 是注册了声明 Interceptor 注解, 并实现 IInterceptor 接口的类, Providers 是注册了声明
Route 注解, 并实现了 IProvider 接口的类
初始化工作都做完了, 总结一下 ARouter 会在编译期根据注解声明分析自动生成一些注入代码, 初始化工作主要是把这些注解的对象和对注解的配置缓存到
Warehouse 的静态对象中.
// 跳转activity的调用
ARouter.getInstance().build("/test/activity2").navigation();
// ARouter.java
public Postcard build(String path) {
return _ARouter.getInstance().build(path);
}
// _ARouter.java
// group 默认是传进来的 path 第一部分内容. 例如 path = /test/activity1, group会默认为 test
// 如果手动声明的,一定要手动传递, 不然会找不到
protected Postcard build(String path, String group) {
return new Postcard(path, group);
}
这里就是直接返回了一个 Postcard 对象, 并保存了path, group. Postcard 是继承了 RouteMeta
navigation方法最后都要调用的 _ARouter.java 中, 中间过程省略.我们直接看核心代码
// _ARouter.java
// postcard 就是前面用build 方法构造的对象实例
// requestCode 是区分 startAcitivity 的方式.如果不为-1, 就用startActivityForResult的方式启动
// NavigationCallback 是对各种状态的回调.
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
try {
// 验证是否能找到对应的 postcard.path
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
// 如果没找到postcard的配置, 调用onLost回调方法, 或者系统配置的"降级服务"(DegradeService)回调
if (null != callback) {
callback.onLost(postcard);
} else {
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
return null;
}
...
}
navigation调用了LogisticsCenter.completion方法做验证, 我们看下 LogisticsCenter.java
这个方法如何验证 postcard, 然后再继续看navigation方法下面的逻辑
// LogisticsCenter.java
public synchronized static void completion(Postcard postcard) {
// 通过postcard 的 path 查找对应的 RouteMeta
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
if (null == routeMeta) {
// 如果没找到, 可能是还没装载过, 需要根据 group 查找对应的 groups
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());
if (null == groupMeta) {
// 如果没找到, 抛出 NoRouteFoundException 错误方法结束
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
// 返回 IRouteGroup 对象, 并调用 loadInto方法.
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
iGroupInstance.loadInto(Warehouse.routes);
// 删除 group 缓存
Warehouse.groupsIndex.remove(postcard.getGroup());
// 重新调用 completion 方法,此时对应的 group 已经缓存完成
completion(postcard); // Reload
}
} else {
// 可以查找到 routeMeta, copy routeMeta 的原始数据到 postcard 中.
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
switch (routeMeta.getType()) {
case PROVIDER:
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
IProvider instance = Warehouse.providers.get(providerMeta);
// 初始化 provider 对象, 并调用初始化方法, 缓存到Warehouse.providers中.
if (null == instance) {
IProvider provider;
try {
provider = providerMeta.getConstructor().newInstance();
provider.init(mContext);
Warehouse.providers.put(providerMeta, provider);
instance = provider;
} catch (Exception e) {
throw new HandlerException("Init provider failed! " + e.getMessage());
}
}
// 设置一个provider 引用
postcard.setProvider(instance);
// provider 默认设置跳过拦截器
postcard.greenChannel();
break;
case FRAGMENT:
// fragment 默认设置跳过拦截器
postcard.greenChannel();
default:
break;
}
}
}
completion方法主要是对 group 做一次懒式加载, 我们继续查看 navigation 方法下面的内容:
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
...
// 执行到这里就是找到了 postcard. 执行对应回调
if (null != callback) {
callback.onFound(postcard);
}
// 如果是"绿色通道", 则直接执行_navigation方法, 目前只有provider, fragment 默认是走绿色通道
if (!postcard.isGreenChannel()) {
// interceptorService 是 ARouter 配置的默认的拦截服务
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
public void onContinue(Postcard postcard) {
_navigation(context, postcard, requestCode, callback);
}
public void onInterrupt(Throwable exception) {
if (null != callback) {
callback.onInterrupt(postcard);
}
}
});
} else {
// 绿色通道
return _navigation(context, postcard, requestCode, callback);
}
return null;
}
interceptorService 是 ARouter
配置的默认的拦截器com.alibaba.android.arouter.core.InterceptorServiceImpl.java
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
// 用线程池异步执行
LogisticsCenter.executor.execute(new Runnable() {
public void run() {
// 初始化一个同步计数类, 用拦截器的 size
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
// 执行拦截操作, 看到这猜是递归调用.直到 index 满足条件, 退出递归.
_excute(0, interceptorCounter, postcard);
// 线程等待计数完成, 等待300秒...
interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
// 判断退出等待后的一些状态...
if (interceptorCounter.getCount() > 0) {
callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
} else if (null != postcard.getTag()) {
callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
} else {
// 没有问题, 继续执行
callback.onContinue(postcard);
}
} catch (Exception e) {
// 中断
callback.onInterrupt(e);
}
}
});
}
我们继续看看_excute方法
private static void _excute(final int index, final CancelableCountDownLatch counter, final Postcard postcard) {
// 递归退出条件
if (index < Warehouse.interceptors.size()) {
// 获取要执行的拦截器
IInterceptor iInterceptor = Warehouse.interceptors.get(index);
// 执行拦截
iInterceptor.process(postcard, new InterceptorCallback() {
public void onContinue(Postcard postcard) {
// 计数器减1
counter.countDown();
// 继续执行下一个拦截
_excute(index + 1, counter, postcard);
}
public void onInterrupt(Throwable exception) {
// 当被拦截后退出递归
postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage());
counter.cancel();
}
});
}
}
和我们猜测的一样, 一个标准的递归调用, 当所有拦截器执行后(假设都不做拦截), 最后还是要回到_navigation方法
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = null == context ? mContext : context;
// 我们就先只分析 activity 的逻辑
switch (postcard.getType()) {
case ACTIVITY:
// 初始化 intent, 把参数也添加上
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());
// Set flags.
int flags = postcard.getFlags();
if (-1 != flags) {
intent.setFlags(flags);
} else if (!(currentContext instanceof Activity)) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
// 在 UI 线程进行 start activity
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
if (requestCode > 0) { // Need start for result
ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
} else {
ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());
}
// 动画设置
if ((0 != postcard.getEnterAnim() || 0 != postcard.getExitAnim()) && currentContext instanceof Activity) { // Old version.
((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());
}
if (null != callback) { // Navigation over.
callback.onArrival(postcard);
}
}
});
break;
}
return null;
}
``````java
// 跳转activity的调用
ARouter.getInstance().build("/test/activity2").navigation();
// ARouter.java
public Postcard build(String path) {
return _ARouter.getInstance().build(path);
}
// _ARouter.java
// group 默认是传进来的 path 第一部分内容. 例如 path = /test/activity1, group会默认为 test
// 如果手动声明的,一定要手动传递, 不然会找不到
protected Postcard build(String path, String group) {
return new Postcard(path, group);
}
这里就是直接返回了一个 Postcard 对象, 并保存了path, group. Postcard 是继承了 RouteMeta
navigation方法最后都要调用的 _ARouter.java 中, 中间过程省略.我们直接看核心代码
// _ARouter.java
// postcard 就是前面用build 方法构造的对象实例
// requestCode 是区分 startAcitivity 的方式.如果不为-1, 就用startActivityForResult的方式启动
// NavigationCallback 是对各种状态的回调.
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
try {
// 验证是否能找到对应的 postcard.path
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
// 如果没找到postcard的配置, 调用onLost回调方法, 或者系统配置的"降级服务"(DegradeService)回调
if (null != callback) {
callback.onLost(postcard);
} else {
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
return null;
}
...
}
navigation调用了LogisticsCenter.completion方法做验证, 我们看下 LogisticsCenter.java
这个方法如何验证 postcard, 然后再继续看navigation方法下面的逻辑
// LogisticsCenter.java
public synchronized static void completion(Postcard postcard) {
// 通过postcard 的 path 查找对应的 RouteMeta
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
if (null == routeMeta) {
// 如果没找到, 可能是还没装载过, 需要根据 group 查找对应的 groups
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());
if (null == groupMeta) {
// 如果没找到, 抛出 NoRouteFoundException 错误方法结束
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
// 返回 IRouteGroup 对象, 并调用 loadInto方法.
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
iGroupInstance.loadInto(Warehouse.routes);
// 删除 group 缓存
Warehouse.groupsIndex.remove(postcard.getGroup());
// 重新调用 completion 方法,此时对应的 group 已经缓存完成
completion(postcard); // Reload
}
} else {
// 可以查找到 routeMeta, copy routeMeta 的原始数据到 postcard 中.
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
switch (routeMeta.getType()) {
case PROVIDER:
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
IProvider instance = Warehouse.providers.get(providerMeta);
// 初始化 provider 对象, 并调用初始化方法, 缓存到Warehouse.providers中.
if (null == instance) {
IProvider provider;
try {
provider = providerMeta.getConstructor().newInstance();
provider.init(mContext);
Warehouse.providers.put(providerMeta, provider);
instance = provider;
} catch (Exception e) {
throw new HandlerException("Init provider failed! " + e.getMessage());
}
}
// 设置一个provider 引用
postcard.setProvider(instance);
// provider 默认设置跳过拦截器
postcard.greenChannel();
break;
case FRAGMENT:
// fragment 默认设置跳过拦截器
postcard.greenChannel();
default:
break;
}
}
}
completion方法主要是对 group 做一次懒式加载, 我们继续查看 navigation 方法下面的内容:
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
...
// 执行到这里就是找到了 postcard. 执行对应回调
if (null != callback) {
callback.onFound(postcard);
}
// 如果是"绿色通道", 则直接执行_navigation方法, 目前只有provider, fragment 默认是走绿色通道
if (!postcard.isGreenChannel()) {
// interceptorService 是 ARouter 配置的默认的拦截服务
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
public void onContinue(Postcard postcard) {
_navigation(context, postcard, requestCode, callback);
}
public void onInterrupt(Throwable exception) {
if (null != callback) {
callback.onInterrupt(postcard);
}
}
});
} else {
// 绿色通道
return _navigation(context, postcard, requestCode, callback);
}
return null;
}
interceptorService 是 ARouter
配置的默认的拦截器com.alibaba.android.arouter.core.InterceptorServiceImpl.java
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
// 用线程池异步执行
LogisticsCenter.executor.execute(new Runnable() {
public void run() {
// 初始化一个同步计数类, 用拦截器的 size
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
// 执行拦截操作, 看到这猜是递归调用.直到 index 满足条件, 退出递归.
_excute(0, interceptorCounter, postcard);
// 线程等待计数完成, 等待300秒...
interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
// 判断退出等待后的一些状态...
if (interceptorCounter.getCount() > 0) {
callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
} else if (null != postcard.getTag()) {
callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
} else {
// 没有问题, 继续执行
callback.onContinue(postcard);
}
} catch (Exception e) {
// 中断
callback.onInterrupt(e);
}
}
});
}
我们继续看看_excute方法
private static void _excute(final int index, final CancelableCountDownLatch counter, final Postcard postcard) {
// 递归退出条件
if (index < Warehouse.interceptors.size()) {
// 获取要执行的拦截器
IInterceptor iInterceptor = Warehouse.interceptors.get(index);
// 执行拦截
iInterceptor.process(postcard, new InterceptorCallback() {
public void onContinue(Postcard postcard) {
// 计数器减1
counter.countDown();
// 继续执行下一个拦截
_excute(index + 1, counter, postcard);
}
public void onInterrupt(Throwable exception) {
// 当被拦截后退出递归
postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage());
counter.cancel();
}
});
}
}
和我们猜测的一样, 一个标准的递归调用, 当所有拦截器执行后(假设都不做拦截), 最后还是要回到_navigation方法
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = null == context ? mContext : context;
// 我们就先只分析 activity 的逻辑
switch (postcard.getType()) {
case ACTIVITY:
// 初始化 intent, 把参数也添加上
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());
// Set flags.
int flags = postcard.getFlags();
if (-1 != flags) {
intent.setFlags(flags);
} else if (!(currentContext instanceof Activity)) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
// 在 UI 线程进行 start activity
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
if (requestCode > 0) { // Need start for result
ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
} else {
ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());
}
// 动画设置
if ((0 != postcard.getEnterAnim() || 0 != postcard.getExitAnim()) && currentContext instanceof Activity) { // Old version.
((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());
}
if (null != callback) { // Navigation over.
callback.onArrival(postcard);
}
}
});
break;
}
return null;
}
主要实现是在LogisticsCenter.completion方法中对IProvider进行了一些分支处理
switch (routeMeta.getType()) {
case PROVIDER:
// 返回实现IProvider接口的类
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
// 在缓存中查找
IProvider instance = Warehouse.providers.get(providerMeta);
// 初始化 provider 对象, 并调用初始化方法, 缓存到Warehouse.providers中.
if (null == instance) {
IProvider provider;
try {
provider = providerMeta.getConstructor().newInstance();
provider.init(mContext);
Warehouse.providers.put(providerMeta, provider);
instance = provider;
} catch (Exception e) {
throw new HandlerException("Init provider failed! " + e.getMessage());
}
}
// 设置一个provider 引用
postcard.setProvider(instance);
// provider 默认设置跳过拦截器
postcard.greenChannel();
break;
// 可以看 _navigation 方法就是直接返回在 completion 方法中是设置的引用
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 PROVIDER:
return postcard.getProvider();
}
return null;
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。