//分析如何跨模块调用API.
ARouter使用时,需要先调用下面方法做初始化操作:
遍历routerMap元素,通过className的检测执行相应class的loadInfo方法. 注意loadInfo的参数,传递的是WareHouse
总结:ARouter.init最终是调用到的LogisticsCenter.init,将通过注解处理器生成的class加载出来,执行class的loadInfo方法,并将信息缓存到WareHouse中。
ARouter初始化完了,接下里看如何使用了。
跟着源码,发现最终是调用的_ARouter.getInstance().build();
回到_ARouter.getInstance().build().因为
小结: ARouter.getInstance().build("/service/hello")。最终获取到一个Postcard.
获取到Postcard后,会执行navigation方法。继续跟进
Postcard.navigation最终是调用_ARouter.getInstance().navigation.
执行按需加载逻辑,从WareHouse.groupsIndex按照key 是service获取到group class.
完善postcard信息:
ARouter使用时,需要先调用下面方法做初始化操作:
ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化
下面跟源码看看init到底做了哪些操作
上图是大概的一个调用时序,可以看到最终在LogisticsCenter做了大量的操作。那LogisticsCenter是什么呢?
Logistics Center,从名字上翻译就是物流中心,整个SDK的流转以及内部调用最终都会下沉到这一层,当然也会按照功能模块进行划分。
进入LogisticsCenter.init方法中看看:
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
try {
Set<String> routerMap;
// These class was generate by arouter-compiler.
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
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_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() + "]");
}
}
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
调用ClassUtils.getFileNameByPakageName方法。扫描
com.alibaba.android.arouter.routes包下面包含的所有的ClassName。
将获取到的className集合保存到routerMap中。
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_PROVIDERS)) {
// Load providerIndex
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
/**
* Storage of route meta and other data.
*
* @author zhilong <a href="mailto:zhilong.lzl@alibaba-inc.com">Contact me.</a>
* @version 1.0
* @since 2017/2/23 下午1:39
*/
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<>();
WareHouse会缓存route,provider.
public void loadInto(Map<String, RouteMeta> providers) {
providers.put("com.router.service.IService", RouteMeta.build(RouteType.PROVIDER, MyService.class, "/service/hello", "service", null, -1, -2147483648));
}
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("service", ARouter\$\$Group\$\$service.class);
}
LogisticsCenter.init分析完毕。
总结:ARouter.init最终是调用到的LogisticsCenter.init,将通过注解处理器生成的class加载出来,执行class的loadInfo方法,并将信息缓存到WareHouse中。
ARouter初始化完了,接下里看如何使用了。
((IService) ARouter.getInstance().build("/service/hello").navigation()).sayHello(this);
上面代码拆开看,先看ARouter.getInstance().build("/service/hello").
跟着源码,发现最终是调用的_ARouter.getInstance().build();
/**
* Build postcard by path and default group
*/
protected Postcard build(String path) {
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
return build(path, extractGroup(path));
}
方法内结果又调用了ARouter.getInstance().navigation(),而navigation最终还是调用的_ARouter.getInstance().navigation()
protected <T> T navigation(Class<? extends T> service) {
try {
Postcard postcard = LogisticsCenter.buildProvider(service.getName());
// Compatible 1.0.5 compiler sdk.
if (null == postcard) { // No service, or this service in old version.
postcard = LogisticsCenter.buildProvider(service.getSimpleName());
}
LogisticsCenter.completion(postcard);
return (T) postcard.getProvider();
} catch (NoRouteFoundException ex) {
logger.warning(Consts.TAG, ex.getMessage());
return null;
}
}
调用LogisticsCenter.buildProvider
public static Postcard buildProvider(String serviceName) {
RouteMeta meta = Warehouse.providersIndex.get(serviceName);
if (null == meta) {
return null;
} else {
return new Postcard(meta.getPath(), meta.getGroup());
}
}
从WareHouse的providersIndex里根据PathReplaceService的className
查找RouterMeta。前面分析Init时,LogisticsCenter.init没有保存PathReplaceService的provider信息。执行各种return。
回到_ARouter.getInstance().build().因为
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
返回的是null,执行
build(path, extractGroup(path));
看看这个build做啥了
protected Postcard build(String path, String group) {
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
return new Postcard(path, group);
}
}
也是先调用navigation,获取到null,最终返回一个Postcard
/**
* A container that contains the roadmap.
*
* @author Alex <a href="mailto:zhilong.liu@aliyun.com">Contact me.</a>
* @version 1.1.0
* @since 16/8/22 19:16
*/
public final class Postcard extends RouteMeta {
// Base
private Uri uri;
private Object tag; // A tag prepare for some thing wrong.
private Bundle mBundle; // Data to transform
private int flags = -1; // Flags of route
private int timeout = 300; // Navigation timeout, TimeUnit.Second
private IProvider provider; // It will be set value, if this postcard was provider.
private boolean greenChannel;
private SerializationService serializationService;
A container that contains the roadmap.
小结: ARouter.getInstance().build("/service/hello")。最终获取到一个Postcard.
ARouter.getInstance().build("/service/hello").navigation()
获取到Postcard后,会执行navigation方法。继续跟进
Postcard.navigation最终是调用_ARouter.getInstance().navigation.
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
.............
LogisticsCenter.completion(postcard);
.................
return _navigation(context, postcard, requestCode, callback);
}
先调用LogisticsCenter.completion方法:
public synchronized static void completion(Postcard postcard) {
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
if(null==routeMeta)
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); // Load route meta.
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
iGroupInstance.loadInto(Warehouse.routes);
completion(postcard); // Reload
}
} else {
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
switch (routeMeta.getType()) {
case PROVIDER: // if the route is provider, should find its instance
// Its provider, so it must be implememt IProvider
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
IProvider instance = Warehouse.providers.get(providerMeta);
if (null == instance) { // There's no instance of this provider
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());
}
}
postcard.setProvider(instance);
postcard.greenChannel(); // Provider should skip all of interceptors
break;
default:
break;
}
}
}
第一步先从
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
查询是不是包含需要的RouteMeta。在ARouter.init初始化时,因为资源和性能上的考虑并没有加载RouteMeta信息到Warehouse中,按需加载。因此此处routeMeta为null。
执行按需加载逻辑,从WareHouse.groupsIndex按照key 是service获取到group class.
routes.put("service", ARouter\$\$Group\$\$service.class);
然后执行ARouter\$\$Group\$\$service的loadInfo方法,传入参数为WareHouse.routes.
iGroupInstance.loadInto(Warehouse.routes)
loadInfo具体实现如下:
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/service/hello", RouteMeta.build(RouteType.PROVIDER, MyService.class, "/service/hello", "service", null, -1, -2147483648));
}
执行完loadInfo后,执行
completion(postcard); // Reload
又回到completion,这次从
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
读取到的routeMeta不为null了,执行else逻辑。
完善postcard信息:
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
处理PROVIDER case:
case PROVIDER: // if the route is provider, should find its instance
// Its provider, so it must be implememt IProvider
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
IProvider instance = Warehouse.providers.get(providerMeta);
if (null == instance) { // There's no instance of this provider
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());
}
}
postcard.setProvider(instance);
根据routeMeta获取到需求依赖的服务类,创建对象,并将对象保存在postcard中。
ARouter.getInstance().build("/service/hello").navigation()
执行上面方法最终会将创建的服务对象,返回给上层。上层拿到服务对象后,执行跨模块调用API。