Arouter解决了什么问题?怎么解决的?
带着这两个问题简单看了一下Arouter的源码。
先说第一个问题,Arouter解决了什么问题?
:组件化中由于依赖关系导致Activity等组件不能直接显式调用问题。
如下图:
这是一个简单的组件化的模型,假设3个model分别有三个Activity:
app——Activity_a
modelA——Activity_b
modelB——Activity_c
正常情况下要实现三个activity之间的跳转可以这样写:
//1.app
startActivity(new Intent(this,Activity_b.class));
//2.modelA
startActivity(new Intent(this,Activity_c.class));
//3.modelB
startActivity(new Intent(this,Activity_a.class));
但实际上由于依赖关系,只有1能实现,而其它两个都会有编译错误。
解决的方式就是共同依赖一个model:router。在router里创建一个容器类,例如:
public class BaseHouse {
public static Map<String,Class<?>> activityHouse=new HashMap<>();
public static void put(String router,Class cl){
activityHouse.put(router,cl);
}
public static Class get(String router){
return activityHouse.get(router);
}
}
在app初始化时,将所有的activity保存
static {
BaseHouse.put("a",Activity_a.class);
BaseHouse.put("b", Activity_b.class);
BaseHouse.put("c", Activity_c.class);
}
而使用时通过索引进行请求:
//1.app
startActivity(new Intent(this,Activity_b.class));
//2.modelA
startActivity(new Intent(this,BaseHouse.get("c"));
//3.modelB
startActivity(new Intent(this,BaseHouse.get("a"));
这样既能使用显示意图,又能解决依赖导致的编译问题,这是我理解的Arouter的基本原理和作用。而关于网上大幅介绍的注解,其实只是锦上添花的操作,是Arouter优秀设计的体现,和原理关系不大。
下面简单看一下Arouter是怎么初始化我们上面提到的索引对应的:
使用前需要先调用ARouter.init()方法进行初始化,跟进该方法:
最终到LogisticsCenter#init方法
/**
* LogisticsCenter init, load all metas in memory. Demand initialization
*/
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
mContext = context;
executor = tpe;
try {
long startInit = System.currentTimeMillis();
//billy.qi modified at 2017-12-06
//load by plugin first
loadRouterMap();
if (registerByPlugin) {
logger.info(TAG, "Load router map by arouter-auto-register plugin.");
} else {
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.
// 1.此处从dex中获取到所有通过注解生成的类
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 {
logger.info(TAG, "Load router map from cache.");
routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
}
logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
startInit = System.currentTimeMillis();
//2.执行对应方法,将索引和类添加到map缓存
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);
}
}
}
logger.info(TAG, "Load root element finished, cost " + (System.currentTimeMillis() - startInit) + " ms.");
if (Warehouse.groupsIndex.size() == 0) {
logger.error(TAG, "No mapping files were found, check your configuration please!");
}
if (ARouter.debuggable()) {
logger.debug(TAG, String.format(Locale.getDefault(), "LogisticsCenter has already been loaded, GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]", Warehouse.groupsIndex.size(), Warehouse.interceptorsIndex.size(), Warehouse.providersIndex.size()));
}
} catch (Exception e) {
throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
}
}
这里比较主要的就是上面两处中文注释的地方,通过上面这一步,索引关系就建立了,最终保存在
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();
}
}
这一步就和上面示例中的BaseHouse的作用对应上了,当然这里相比示例进行了一些包装,使Arouter的功能更加丰富,但是原理不变。