首先我們都知道 ARouter是以路由的方式實(shí)現(xiàn)組件間(組件化項(xiàng)目)通訊的的框架鳞溉。
路由的本質(zhì)务豺,是映射和尋址棒旗,收集所有的注冊(cè)類(lèi)痊乾,生成字符串和注冊(cè)類(lèi)的映射關(guān)系皮壁,這樣就可以通過(guò)字符串找到對(duì)應(yīng)的類(lèi).
解決的問(wèn)題,沒(méi)有依賴(lài)關(guān)系的兩個(gè)模塊哪审,不能直接交互蛾魄,路由提供了倉(cāng)庫(kù),可以通過(guò)字符串找到注入倉(cāng)庫(kù)的類(lèi)湿滓,解決類(lèi)模塊間交互的問(wèn)題(組件間通訊)
如何分組和構(gòu)建路由表的呢滴须?
一.從使用說(shuō)起
-
我們按照文檔使用ARouter 的時(shí)候注意到, 使用@Route注解的模塊茉稠,需要在modeule 的build.gradle里添加:
defaultConfig { javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] } } }
沒(méi)有這段代碼會(huì)在build項(xiàng)目時(shí)爆錯(cuò):
These no module name, at 'build.gradle', like : ...
-
必須在每個(gè)使用@Route 注解的模塊里都引入ARouter的注解處理器描馅,否則這個(gè)模塊里注解不會(huì)被處理
annotationProcessor 'com.alibaba:arouter-compiler:1.5.2'
-
@Route 注解的path 至少需要有兩級(jí)
@Route(path = "/test/activity") public class YourActivity extend Activity { ... }
否則toast提示:“There's no route matched! Path = [/xxx/xxx] Group = [xxxx]”
編譯生成的類(lèi):
Root類(lèi)
group類(lèi)
* ARouter$Root$$xxx(modulename) 把所有的組(ARouter$Group$xxx) put到Map集合里(routers)
* ARouter$Group$$xxx(groupname) 把一個(gè)分組下的所有路徑(RouteMeta)存入map
* ARouter$Providers$$xxx(modulename) 把注冊(cè)的接口存入map
二.ARouter 注解處理器:RouteProcessor
有注解就有注解處理器,ARouter也是基于APT而线,構(gòu)建路由表的邏輯就在RouteProcessor铭污,也是在RouteProcessor里生成了上面的那些類(lèi)
APT 和 javapoat 有同學(xué)分享過(guò)恋日,這也是APT 和 javapoat的一次應(yīng)用
-
BaseProcessor
RouteProcessor 繼承了 BaseProcessor
public abstract class BaseProcessor extends AbstractProcessor { ... // 模塊名 String moduleName = null; //是否需要生成router 文檔 boolean generateDoc; @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); //初始化工具類(lèi) mFiler = processingEnv.getFiler(); types = processingEnv.getTypeUtils(); elementUtils = processingEnv.getElementUtils(); typeUtils = new TypeUtils(types, elementUtils); logger = new Logger(processingEnv.getMessager()); // Attempt to get user configuration [moduleName] Map<String, String> options = processingEnv.getOptions(); if (MapUtils.isNotEmpty(options)) { //從options里獲取 moduleName moduleName = options.get(KEY_MODULE_NAME); generateDoc = VALUE_ENABLE.equals(options.get(KEY_GENERATE_DOC_NAME)); } if (StringUtils.isNotEmpty(moduleName)) { moduleName = moduleName.replaceAll("[^0-9a-zA-Z_]+", ""); } else { 。嘹狞。岂膳。 } } ... @Override public Set<String> getSupportedOptions() { return new HashSet<String>() {{ this.add(KEY_MODULE_NAME); this.add(KEY_GENERATE_DOC_NAME); }}; } }
主要初始化工具類(lèi),從gradle 配置里獲取 moduleName
-
getSupportedOptions()
KEY_MODULE_NAME的值:
// Options of processor public static final String KEY_MODULE_NAME = "AROUTER_MODULE_NAME"; public static final String KEY_GENERATE_DOC_NAME = "AROUTER_GENERATE_DOC";
就是我們?cè)赽uild.gradle里配置的 AROUTER_MODULE_NAME
2493821365b453ece9e5cca9.png -
init()
從 options 里獲取 moduleName磅网,如果moduleName為空拋出異常谈截; 異常信息就是這段字符串:
2493821354ae74e74f7443f0.png
這就是為什么如果不在build.gradle里配置AROUTER_MODULE_NAME,會(huì)異常的原因涧偷, moduleName有什么用簸喂?
-
RouteProcessor
public class RouteProcessor extends BaseProcessor { private Map<String, Set<RouteMeta>> groupMap = new HashMap<>(); // ModuleName and routeMeta. private Map<String, String> rootMap = new TreeMap<>(); // Map of root metas, used for generate class file in order. private TypeMirror iProvider = null; @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); // iProvider = elementUtils.getTypeElement(Consts.IPROVIDER).asType(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (CollectionUtils.isNotEmpty(annotations)) { Set<? extends Element> routeElements = roundEnv.getElementsAnnotatedWith(Route.class); try { this.parseRoutes(routeElements); } catch (Exception e) { } return true; } return false; } }
創(chuàng)建兩個(gè)map,分別用來(lái)存放當(dāng)前模塊下所有的分組(rootMap)燎潮,和每個(gè)分組下的路徑(groupMap)
private Map<String, Set<RouteMeta>> groupMap = new HashMap<>();
private Map<String, String> rootMap = new TreeMap<>();process()方法調(diào)用了parseRoutes()方法喻鳄,處理注解的邏輯在這個(gè)方里
獲取activity/fragment/service 的類(lèi)型,用于后面的類(lèi)型判斷
private void parseRoutes(Set<? extends Element> routeElements) throws IOException { if (CollectionUtils.isNotEmpty(routeElements)) { // prepare the type an so on. logger.info(">>> Found routes, size is " + routeElements.size() + " <<<"); rootMap.clear(); TypeMirror type_Activity = elementUtils.getTypeElement(ACTIVITY).asType(); TypeMirror type_Service = elementUtils.getTypeElement(SERVICE).asType(); TypeMirror fragmentTm = elementUtils.getTypeElement(FRAGMENT).asType(); TypeMirror fragmentTmV4 = elementUtils.getTypeElement(Consts.FRAGMENT_V4).asType(); // Interface of ARouter TypeElement type_IRouteGroup = elementUtils.getTypeElement(IROUTE_GROUP); TypeElement type_IProviderGroup = elementUtils.getTypeElement(IPROVIDER_GROUP); ClassName routeMetaCn = ClassName.get(RouteMeta.class); ClassName routeTypeCn = ClassName.get(RouteType.class);
創(chuàng)建 RouteMeta 對(duì)象确封,RouteMeta主要存放的是路徑信息除呵,包含了Rout注解的值,activity/fragment/service枚舉爪喘,className颜曾,以及跳轉(zhuǎn)參數(shù)信息。
for (Element element : routeElements) { TypeMirror tm = element.asType(); Route route = element.getAnnotation(Route.class); RouteMeta routeMeta; //6秉剑。注解的是 Activity or Fragment if (types.isSubtype(tm, type_Activity) || types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) { // Get all fields annotation by @Autowired Map<String, Integer> paramsType = new HashMap<>(); Map<String, Autowired> injectConfig = new HashMap<>(); // 7泛豪。收集 @Autowired 注解的參數(shù) injectParamCollector(element, paramsType, injectConfig); if (types.isSubtype(tm, type_Activity)) { // Activity logger.info(">>> Found activity route: " + tm.toString() + " <<<"); routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType); } else { // Fragment logger.info(">>> Found fragment route: " + tm.toString() + " <<<"); routeMeta = new RouteMeta(route, element, RouteType.parse(FRAGMENT), paramsType); } routeMeta.setInjectConfig(injectConfig); } else if (types.isSubtype(tm, iProvider)) { // IProvider(接口) logger.info(">>> Found provider route: " + tm.toString() + " <<<"); routeMeta = new RouteMeta(route, element, RouteType.PROVIDER, null); } else if (types.isSubtype(tm, type_Service)) { // Service logger.info(">>> Found service route: " + tm.toString() + " <<<"); routeMeta = new RouteMeta(route, element, RouteType.parse(SERVICE), null); } else { throw new RuntimeException("The @Route is marked on unsupported class, look at [" + tm.toString() + "]."); } // 7。routeMeta(路徑信息)存入groupMap categories(routeMeta); }
1.先判斷路徑path是否合法秃症;然后把RouteMeta按groupName分組存入 groupMap
private void categories(RouteMeta routeMete) { //驗(yàn)證routeMete if (routeVerify(routeMete)) { logger.info(">>> Start categories, group = " + routeMete.getGroup() + ", path = " + routeMete.getPath() + " <<<"); Set<RouteMeta> routeMetas = groupMap.get(routeMete.getGroup()); if (CollectionUtils.isEmpty(routeMetas)) { Set<RouteMeta> routeMetaSet = new TreeSet<>(new Comparator<RouteMeta>() { @Override public int compare(RouteMeta r1, RouteMeta r2) { try { return r1.getPath().compareTo(r2.getPath()); } catch (NullPointerException npe) { logger.error(npe.getMessage()); return 0; } } }); routeMetaSet.add(routeMete); groupMap.put(routeMete.getGroup(), routeMetaSet); } else { routeMetas.add(routeMete); } } else { logger.warning(">>> Route meta verify error, group is " + routeMete.getGroup() + " <<<"); } }
判斷路徑方法 候址,從下面這段代碼知道了
path 必須“/”開(kāi)頭,并且第一段作為默認(rèn) group 名种柑;
private boolean routeVerify(RouteMeta meta) {
String path = meta.getPath();
if (StringUtils.isEmpty(path) || !path.startsWith("/")) { // The path must be start with '/' and not empty!
return false;
}
if (StringUtils.isEmpty(meta.getGroup())) { // Use default group(the first word in path)
try {
String defaultGroup = path.substring(1, path.indexOf("/", 1));
if (StringUtils.isEmpty(defaultGroup)) {
return false;
}
meta.setGroup(defaultGroup);
return true;
} catch (Exception e) {
logger.error("Failed to extract default group! " + e.getMessage());
return false;
}
}
return true;
}
開(kāi)始生成代碼
for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) {
//組名
String groupName = entry.getKey();
// 構(gòu)建方法
/**
* @Override
* public void loadInto(Map<String, RouteMeta> providers);
*/
MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(groupParamSpec);
List<RouteDoc> routeDocList = new ArrayList<>();
Set<RouteMeta> groupData = entry.getValue();
for (RouteMeta routeMeta : groupData) {
// Build group method body
RouteDoc routeDoc = extractDocInfo(routeMeta);
ClassName className = ClassName.get((TypeElement) routeMeta.getRawType());
// 構(gòu)建跳轉(zhuǎn)參數(shù)的map
StringBuilder mapBodyBuilder = new StringBuilder();
Map<String, Integer> paramsType = routeMeta.getParamsType();
Map<String, Autowired> injectConfigs = routeMeta.getInjectConfig();
if (MapUtils.isNotEmpty(paramsType)) {
List<RouteDoc.Param> paramList = new ArrayList<>();
for (Map.Entry<String, Integer> types : paramsType.entrySet()) {
mapBodyBuilder.append("put(\"").append(types.getKey()).append("\", ").append(types.getValue()).append("); ");
RouteDoc.Param param = new RouteDoc.Param();
Autowired injectConfig = injectConfigs.get(types.getKey());
param.setKey(types.getKey());
param.setType(TypeKind.values()[types.getValue()].name().toLowerCase());
param.setDescription(injectConfig.desc());
param.setRequired(injectConfig.required());
paramList.add(param);
}
routeDoc.setParams(paramList);
}
String mapBody = mapBodyBuilder.toString();
//生成 map的 put 代碼
loadIntoMethodOfGroupBuilder.addStatement(
"atlas.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, " + (StringUtils.isEmpty(mapBody) ? null : ("new java.util.HashMap<String, Integer>(){{" + mapBodyBuilder.toString() + "}}")) + ", " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
routeMeta.getPath(),
routeMetaCn,
routeTypeCn,
className,
routeMeta.getPath().toLowerCase(),
routeMeta.getGroup().toLowerCase());
routeDoc.setClassName(className.toString());
routeDocList.add(routeDoc);
}
// 生成ARouter$Group$文件
String groupFileName = NAME_OF_GROUP + groupName;
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(groupFileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(type_IRouteGroup))
.addModifiers(PUBLIC)
.addMethod(loadIntoMethodOfGroupBuilder.build())
.build()
).build().writeTo(mFiler);
logger.info(">>> Generated group: " + groupName + "<<<");
rootMap.put(groupName, groupFileName);
docSource.put(groupName, routeDocList);
}
上面這段代碼生成類(lèi) ARouter$$Group$login岗仑,groupname = login;
public class ARouter$$Group$xxx(groupname) implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/login/loginX", RouteMeta.build(RouteType.ACTIVITY, LoginActivity.class, "/login/loginx", "login", null, -1, -2147483648));
atlas.put("/login/register", RouteMeta.build(RouteType.ACTIVITY, RegisterActivity.class, "/login/register", "login", null, -1, -2147483648))聚请;
}
}
有多少group就有多少這樣的類(lèi)荠雕,然后把這些類(lèi)名存入rootMap
if (MapUtils.isNotEmpty(rootMap)) {
// Generate root meta by group name, it must be generated before root, then I can find out the class of group.
for (Map.Entry<String, String> entry : rootMap.entrySet()) {
loadIntoMethodOfRootBuilder.addStatement("routes.put($S, $T.class)", entry.getKey(), ClassName.get(PACKAGE_OF_GENERATE_FILE, entry.getValue()));
}
}
// Write provider into disk
String providerMapFileName = NAME_OF_PROVIDER + SEPARATOR + moduleName;
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(providerMapFileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(type_IProviderGroup))
.addModifiers(PUBLIC)
.addMethod(loadIntoMethodOfProviderBuilder.build())
.build()
).build().writeTo(mFiler);
上面這段代碼,我們看到了moduleName,也就是gradle里的project.getName()驶赏,這段代碼生成下面這個(gè)類(lèi)炸卑, moduleName =“LoginSDK”
public class ARouter$$Providers$$LoginSDK implements IProviderGroup {
@Override
public void loadInto(Map<String, RouteMeta> providers) {
providers.put("com.example.loginsdk.IUserInfo", RouteMeta.build(RouteType.PROVIDER, UserInfoManager.class, "/interface/user", "interface", null, -1, -2147483648));
}
}
可以看到這個(gè)類(lèi)命名:ARouter+Providers+moduleName,Module里只有一個(gè)這樣的類(lèi)煤傍,把這個(gè)模塊里注冊(cè)的接口(接口都繼承IProvider)put到map集合里
接著生成root
String rootFileName = NAME_OF_ROOT + SEPARATOR + moduleName;
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(rootFileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(elementUtils.getTypeElement(ITROUTE_ROOT)))
.addModifiers(PUBLIC)
.addMethod(loadIntoMethodOfRootBuilder.build())
.build()
).build().writeTo(mFiler);
rootFileName =“ARouter$$Root$LoginSDK”盖文,其中moduleName = LoginSDK
最終生成的類(lèi)是:
public class ARouter$$Root$$LoginSDK implements IRouteRoot {
@Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("interface", ARouter$$Group$$interface.class);
routes.put("login", ARouter$$Group$$login.class);
}
}
這個(gè)類(lèi)也只有一個(gè),把前面生成的所有 ARouter$Group 都類(lèi)存入map蚯姆,到此就完所有注解的分組和映射五续。
模塊間以modleName分離洒敏,每個(gè)模塊有多個(gè)組,分組能夠更好的管理和查找路由信息疙驾。
映射關(guān)系構(gòu)建好了凶伙,類(lèi)文件創(chuàng)建出來(lái), 什么時(shí)候加載調(diào)用的呢它碎?
三函荣、ARouter 初始化
一般在application里初始化
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
ARouter.openDebug();
ARouter.init(this);
}
開(kāi)發(fā)過(guò)程中如果沒(méi)有 開(kāi)啟 ARouter.openDebug();會(huì)發(fā)現(xiàn)新增的path 跳轉(zhuǎn)不了,但是release可以跳轉(zhuǎn)
來(lái)看看init ()方法
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.");
}
調(diào)用里 _ARouter.init(application)
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;
}
_ARouter 又調(diào)用了 LogisticsCenter.init(mContext, executor)扳肛,并傳入了一個(gè)線程池
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
mContext = context;
executor = tpe;
try {
long startInit = System.currentTimeMillis();
//load by plugin first
loadRouterMap();
//使用gradle插件自動(dòng)處理了
if (registerByPlugin) {
logger.info(TAG, "Load router map by arouter-auto-register plugin.");
} else {
//手動(dòng)處理
Set<String> routerMap;
// It will rebuild router map every times when debuggable.
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
// These class was generated by arouter-compiler.
//通過(guò)指定包名傻挂,掃描包下面包含的所有的ClassName
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>()));
}
。敞峭。踊谋。
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() + "]");
}
}
有個(gè)getFileNameByPackageName()方法
public static Set<String> getFileNameByPackageName(Context context, final String packageName) throws PackageManager.NameNotFoundException, IOException, InterruptedException {
final Set<String> classNames = new HashSet<>();
List<String> paths = getSourcePaths(context);
final CountDownLatch parserCtl = new CountDownLatch(paths.size());
for (final String path : paths) {
DefaultPoolExecutor.getInstance().execute(new Runnable() {
@Override
public void run() {
DexFile dexfile = null;
try {
if (path.endsWith(EXTRACTED_SUFFIX)) {
//NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache"
dexfile = DexFile.loadDex(path, path + ".tmp", 0);
} else {
dexfile = new DexFile(path);
}
Enumeration<String> dexEntries = dexfile.entries();
while (dexEntries.hasMoreElements()) {
String className = dexEntries.nextElement();
if (className.startsWith(packageName)) {
classNames.add(className);
}
}
轿衔。沉迹。。
}
});
}
parserCtl.await();
return classNames;
}
通過(guò)指定包名害驹,掃描包下面所有的文件ClassName鞭呕;在編譯階段注解處理器在“com.alibaba.android.arouter.routes”這個(gè)包下面生成了文件,通過(guò)這個(gè)方法就可以?huà)呙柽@個(gè)包下所有的類(lèi)名宛官;掃描的操作是運(yùn)行在線程池里的葫松,與_ARouter里的線程池是同一個(gè)
在這之前有個(gè)判斷條件:
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)),如果開(kāi)啟了ARouter.openDebug()或者 項(xiàng)目的版本有變化底洗,則重新生成routerMap并且存入sp腋么,否則直接用sp里的緩存,新增的path不會(huì)被加載亥揖,這解釋了上面出現(xiàn)不能跳轉(zhuǎn)的問(wèn)題珊擂。
繼續(xù)
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);
}
}
可以看到init()里加載了 ARouter$Providers$、ARouter$Root费变、ARouter$Interceptors摧扇,但是沒(méi)有加載任何一個(gè)ARouter$Group;那group是什么時(shí)候加載的呢
四、navigation()
如何根據(jù)path找到跳轉(zhuǎn)目標(biāo)(尋址)挚歧?
ARouter.getInstance().build("login/loginX").navigation();
build()會(huì)進(jìn)入 _ARouter.build(String path)
protected Postcard build(String path) {
if (TextUtils.isEmpty(path)) {
throw new HandlerException(Consts.TAG + "Parameter is invalid!");
} else {
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
return build(path, extractGroup(path), true);
}
}
這里有個(gè)方法扛稽,可以看到path 必須以“/”開(kāi)頭且至少兩段,否則會(huì)拋異常
private String extractGroup(String path) {
if (TextUtils.isEmpty(path) || !path.startsWith("/")) {
throw new HandlerException(Consts.TAG + "Extract the default group failed, the path must be start with '/' and contain more than 2 '/'!");
}
try {
String defaultGroup = path.substring(1, path.indexOf("/", 1));
if (TextUtils.isEmpty(defaultGroup)) {
throw new HandlerException(Consts.TAG + "Extract the default group failed! There's nothing between 2 '/'!");
} else {
return defaultGroup;
}
} catch (Exception e) {
logger.warning(Consts.TAG, "Failed to extract default group! " + e.getMessage());
return null;
}
}
build()方法創(chuàng)建了Postcard對(duì)象滑负,然后看Postcard.navigation()
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
// Pretreatment failed, navigation canceled.
return null;
}
// Set context to postcard.
postcard.setContext(null == context ? mContext : context);
try {
LogisticsCenter.completion(postcard);
這里調(diào)用了 LogisticsCenter.completion(postcard) 在张,找到跳轉(zhuǎn)目標(biāo)锡搜,給postcart賦值
public synchronized static void completion(Postcard postcard) {
if (null == postcard) {
throw new NoRouteFoundException(TAG + "No postcard!");
}
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
if (null == routeMeta) {
// Maybe its does't exist, or didn't load.
if (!Warehouse.groupsIndex.containsKey(postcard.getGroup())) {
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
try {
。瞧掺。耕餐。
addRouteGroupDynamic(postcard.getGroup(), null);
。辟狈。肠缔。
} catch (Exception e) {
。哼转。明未。
}
completion(postcard); // Reload
}
} else {
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
。壹蔓。趟妥。
}
}
Warehouse.routes如果已經(jīng)加載了path,直接賦值給postcard佣蓉,如果沒(méi)找到但是在Warehouse.groupsIndex里有這個(gè)group(Warehouse.groupsIndex是在init()里添加元素的披摄,ARouter$$Root$xxx這個(gè)類(lèi)的loadInto()方法里) 就會(huì)執(zhí)行
addRouteGroupDynamic(postcard.getGroup(), null)方法
public synchronized static void addRouteGroupDynamic(String groupName, IRouteGroup group) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
if (Warehouse.groupsIndex.containsKey(groupName)){
// If this group is included, but it has not been loaded
// load this group first, because dynamic route has high priority.
Warehouse.groupsIndex.get(groupName).getConstructor().newInstance().loadInto(Warehouse.routes);
Warehouse.groupsIndex.remove(groupName);
}
// cover old group.
if (null != group) {
group.loadInto(Warehouse.routes);
}
}
Warehouse.groupsIndex.get(groupName).getConstructor().newInstance().loadInto(Warehouse.routes);
加載一個(gè)ARouter$$Group$xxx 類(lèi),調(diào)用其loadInto()方法給Warehouse.routes添加元素 勇凭,尋址完成疚膊。
看到這里我們就知道了ARouter$Group$xxx是在調(diào)用ARouter.getInstance().build(“/group/path”).navigation()時(shí)候加載,使用時(shí)才加載虾标。
跳轉(zhuǎn):
_ARouter._navigation().startActivity()
private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = postcard.getContext();
switch (postcard.getType()) {
case ACTIVITY:
// Build intent
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());
// Set flags.
int flags = postcard.getFlags();
if (0 != flags) {
intent.setFlags(flags);
}
// Non activity, need FLAG_ACTIVITY_NEW_TASK
if (!(currentContext instanceof Activity)) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
// Set Actions
String action = postcard.getAction();
if (!TextUtils.isEmpty(action)) {
intent.setAction(action);
}
// Navigation in main looper.
runInMainThread(new Runnable() {
@Override
public void run() {
startActivity(requestCode, currentContext, intent, postcard, callback);
}
});
總結(jié)
- ARouter 編譯期間構(gòu)建路由表和映射關(guān)系寓盗,分模塊分組;
- 有自己的線程池璧函,編譯完成后掃描dex文件傀蚌,掃出apt生成的文件的類(lèi)名
- 初始化只加載了 ARouter$Providers$、ARouter$Root$蘸吓、ARouter$Interceptors善炫,;ARouter$Group 在第一次使用時(shí)加載。