ARouter是阿里巴巴出品,幫助 Android App 進(jìn)行組件化改造的路由框架颅湘,我們項(xiàng)目也使用的是ARouter路由框架進(jìn)行解耦;
我打算分三部分進(jìn)行解析ARouter框架:
第一部分:代碼生成
第二部分:路由加載
第三部分:路由跳轉(zhuǎn)
第一部分:代碼生成
ARouter
使用annotationProcessor
配合JavaPoet進(jìn)行代碼生成;annotationProcessor
顧名思義是注解處理器的意思置鼻。它對(duì)源代碼文件進(jìn)行檢測找出其中的Annotation,根據(jù)注解自動(dòng)生成代碼蜓竹。 Annotation
處理器在處理Annotation
時(shí)可以根據(jù)源文件中的Annotation
生成額外的源文件和其它的文件箕母,之后將編譯生成的源文件和原來的源文件一起生成class
文件。由于annotationProcessor
不屬于本篇范疇請(qǐng)點(diǎn)擊這里查看詳細(xì)用法俱济。
上圖為ARouter annotationProcessor的代碼嘶是;
AutowiredProcessor
AutowiredProcessor
類的作用是根據(jù)Autowired
注解的字段和這個(gè)注解字段的外圍類來生成對(duì)應(yīng)的類,生成的這個(gè)類命名方式為ClassName+\$$ARouter$$Autowired
蛛碌,并且實(shí)現(xiàn)接口implements ISyringe
的public void inject(Object target)
方法聂喇。ARouter.getInstance().inject(this);
底層就調(diào)用的是這個(gè)inject
方法。
如果上面這段文字很難理解請(qǐng)看下面源碼解析一目了然:
注解類
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Autowired {
// Mark param's name or service name.
//用來指定獲取數(shù)據(jù)的名字蔚携,如果不設(shè)置直接用字段的名字獲取數(shù)據(jù)
String name() default "";
// If required, app will be crash when value is null.
// Primitive type wont be check!
//true希太,如果被修飾的字段沒有獲取到數(shù)據(jù)會(huì)拋出異常
boolean required() default false;
// Description of the field
//對(duì)這個(gè)字段進(jìn)行解釋,可以生成javadoc
String desc() default "No desc.";
}
文件處理的入口方法
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (CollectionUtils.isNotEmpty(set)) {
try {
logger.info(">>> Found autowired field, start... <<<");
//根據(jù)注解處理源碼酝蜒,生成Map<TypeElement, List<Element>>形式的map誊辉,
// TypeElement為Autowired字段修飾的外圍類,List<Element>為這個(gè)外圍類中Autowired修飾的所有字段
categories(roundEnvironment.getElementsAnnotatedWith(Autowired.class));
//根據(jù)上個(gè)方法生成的結(jié)構(gòu)來創(chuàng)建java類
generateHelper();
} catch (Exception e) {
logger.error(e);
}
return true;
}
return false;
}
處理注解字段和外圍類的方法
private void categories(Set<? extends Element> elements) throws IllegalAccessException {
if (CollectionUtils.isNotEmpty(elements)) {
for (Element element : elements) {
//獲取這個(gè)element的外圍類
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
if (element.getModifiers().contains(Modifier.PRIVATE)) {
throw new IllegalAccessException("The autowired fields CAN NOT BE 'private'!!! please check field ["
+ element.getSimpleName() + "] in class [" + enclosingElement.getQualifiedName() + "]");
}
//判斷外圍類是否存在
if (parentAndChild.containsKey(enclosingElement)) { // Has categries
//如果存在直接將Autowired注解修飾的字段添加到這個(gè)外圍類中
parentAndChild.get(enclosingElement).add(element);
} else {
//如果外圍類不存在亡脑,創(chuàng)建
List<Element> childs = new ArrayList<>();
childs.add(element);
parentAndChild.put(enclosingElement, childs);
}
}
logger.info("categories finished.");
}
}
根據(jù)上面方法過濾出的結(jié)構(gòu)創(chuàng)建文件的方法
private void generateHelper() throws IOException, IllegalAccessException {
TypeElement type_ISyringe = elements.getTypeElement(ISYRINGE);
TypeElement type_JsonService = elements.getTypeElement(JSON_SERVICE);
TypeMirror iProvider = elements.getTypeElement(Consts.IPROVIDER).asType();
TypeMirror activityTm = elements.getTypeElement(Consts.ACTIVITY).asType();
TypeMirror fragmentTm = elements.getTypeElement(Consts.FRAGMENT).asType();
TypeMirror fragmentTmV4 = elements.getTypeElement(Consts.FRAGMENT_V4).asType();
// Build input param name.
//方法參數(shù)為 (Object target)
ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build();
if (MapUtils.isNotEmpty(parentAndChild)) {
for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) {
// Build method : 'inject'
/**
* 創(chuàng)建的方法為
* Override
* public void inject(Object target);
*/
MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder(METHOD_INJECT)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(objectParamSpec);
//外圍類
TypeElement parent = entry.getKey();
//所有注解的字段
List<Element> childs = entry.getValue();
//獲取外圍類包名加類的名字堕澄,例如:com.arouter.demo.Test1Activity
String qualifiedName = parent.getQualifiedName().toString();
//獲取包名例如:com.arouter.demo
String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf("."));
//拼接生成類的名字Test1Activity$$ARouter$$Autowired
String fileName = parent.getSimpleName() + NAME_OF_AUTOWIRED;
logger.info(">>> Start process " + childs.size() + " field in " + parent.getSimpleName() + " ... <<<");
//類的信息 javadoc public class Test1Activity$$ARouter$$Autowired implements ISyringe
TypeSpec.Builder helper = TypeSpec.classBuilder(fileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(type_ISyringe))
.addModifiers(PUBLIC);
//創(chuàng)建字段 private SerializationService serializationService;
FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService", Modifier.PRIVATE).build();
helper.addField(jsonServiceField);
/**
* 在方法體內(nèi)創(chuàng)建賦值代碼
* serializationService = ARouter.getInstance().navigation(ARouter.class);
* Test1Activity substitute = (Test1Activity)target;
*/
injectMethodBuilder.addStatement("serializationService = $T.getInstance().navigation($T.class);", ARouterClass, ClassName.get(type_JsonService));
injectMethodBuilder.addStatement("$T substitute = ($T)target", ClassName.get(parent), ClassName.get(parent));
// Generate method body, start inject.
for (Element element : childs) {
Autowired fieldConfig = element.getAnnotation(Autowired.class);
String fieldName = element.getSimpleName().toString();
if (types.isSubtype(element.asType(), iProvider)) { // It's provider
//如果繼承IProvider
//判斷Autowired是否寫了name,如果寫了就取name值獲取數(shù)據(jù)霉咨,如果沒寫就用field字段本身的名字獲取數(shù)據(jù)
if ("".equals(fieldConfig.name())) { // User has not set service path, then use byType.
// Getter
//substitute.fieldName = ARouter.getInstance().navigation(ARouter.class);
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = $T.getInstance().navigation($T.class)",
ARouterClass,
ClassName.get(element.asType())
);
} else { // use byName
// Getter
//substitute.fieldName = ARouter.getInstance().navigation(ARouter.class);
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = ($T)$T.getInstance().build($S).navigation();",
ClassName.get(element.asType()),
ARouterClass,
fieldConfig.name()
);
}
// Validater
//如果Autowired中的required返回true蛙紫,那么fieldName
if (fieldConfig.required()) {
injectMethodBuilder.beginControlFlow("if (substitute." + fieldName + " == null)");
injectMethodBuilder.addStatement(
"throw new RuntimeException(\"The field '" + fieldName + "' is null, in class '\" + $T.class.getName() + \"!\")", ClassName.get(parent));
injectMethodBuilder.endControlFlow();
}
} else { // It's normal intent value
String statment = "substitute." + fieldName + " = substitute.";
boolean isActivity = false;
if (types.isSubtype(parent.asType(), activityTm)) { // Activity, then use getIntent()
isActivity = true;
statment += "getIntent().";
} else if (types.isSubtype(parent.asType(), fragmentTm) || types.isSubtype(parent.asType(), fragmentTmV4)) { // Fragment, then use getArguments()
statment += "getArguments().";
} else {
throw new IllegalAccessException("The field [" + fieldName + "] need autowired from intent, its parent must be activity or fragment!");
}
/**
* 如上代碼判斷如果是activity就用getIntent()形式
* 如果是fragment就用getArguments()形式
* substitute.fieldName = substitute.getIntent().getStringExtra(); //如下1可以由多種形式,下面展示了兩種形式
* serializationService.json2Object(substitute.getIntent().getStringExtra($S), $T.class)";
* if (null != serializationService){ //如2
* substitute.fieldName = serializationService.json2Object(substitute.getIntent().getStringExtra($S), $T.class)";
* }else{
* ARouter.e("ARouter::",You want automatic inject the field 'fieldName' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!\")"
* }
*/
statment = buildStatement(statment, typeUtils.typeExchange(element), isActivity); //1
if (statment.startsWith("serializationService.")) { // Not mortals
injectMethodBuilder.beginControlFlow("if (null != serializationService)"); //2
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = " + statment,
(StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name()),
ClassName.get(element.asType())
);
injectMethodBuilder.nextControlFlow("else");
injectMethodBuilder.addStatement(
"$T.e(\"" + Consts.TAG + "\", \"You want automatic inject the field '" + fieldName + "' in class '$T' , then you should implement 'SerializationService' to support object auto inject!\")", AndroidLog, ClassName.get(parent));
injectMethodBuilder.endControlFlow();
} else {
//substitute.fieldName = substitute.getIntent().getStringExtra();
injectMethodBuilder.addStatement(statment, StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name());
}
// Validator
//如果Autowired.required返回true途戒,那么對(duì)這個(gè)字段進(jìn)行強(qiáng)制校驗(yàn)坑傅,判斷為null拋出異常
if (fieldConfig.required() && !element.asType().getKind().isPrimitive()) { // Primitive wont be check.
injectMethodBuilder.beginControlFlow("if (null == substitute." + fieldName + ")");
injectMethodBuilder.addStatement(
"$T.e(\"" + Consts.TAG + "\", \"The field '" + fieldName + "' is null, in class '\" + $T.class.getName() + \"!\")", AndroidLog, ClassName.get(parent));
injectMethodBuilder.endControlFlow();
}
}
}
helper.addMethod(injectMethodBuilder.build());
// Generate autowire helper
JavaFile.builder(packageName, helper.build()).build().writeTo(mFiler);
logger.info(">>> " + parent.getSimpleName() + " has been processed, " + fileName + " has been generated. <<<");
}
logger.info(">>> Autowired processor stop. <<<");
}
}
通過如下兩段代碼來看源文件和生成之后的文件
源文件
@Route(path = "/test/fragment")
public class BlankFragment extends Fragment {
@Autowired
String name;
@Autowired(required = true)
TestObj obj;
public BlankFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView textView = new TextView(getActivity());
return textView;
}
}
生成之后的文件
**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class BlankFragment$$ARouter$$Autowired implements ISyringe {
private SerializationService serializationService;
@Override
public void inject(Object target) {
serializationService = ARouter.getInstance().navigation(SerializationService.class);;
BlankFragment substitute = (BlankFragment)target;
substitute.name = substitute.getArguments().getString("name");
if (null != serializationService) {
substitute.obj = serializationService.json2Object(substitute.getArguments().getString("obj"), TestObj.class);
} else {
Log.e("ARouter::", "You want automatic inject the field 'obj' in class 'BlankFragment' , then you should implement 'SerializationService' to support object auto inject!");
}
if (null == substitute.obj) {
Log.e("ARouter::", "The field 'obj' is null, in class '" + BlankFragment.class.getName() + "!");
}
}
}
InterceptorProcessor
InterceptorProcessor
類的作用是根據(jù)Interceptor
注解的類來生成對(duì)應(yīng)的類,生成的這個(gè)類命名方式為ARouter$$Interceptors$$moduleName
其中moduleName為build.gradle中配置的喷斋,并且實(shí)現(xiàn)接口implements IInterceptorGroup
的public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors)
方法唁毒。在ARouter初始化的時(shí)候通過這個(gè)類的這個(gè)方法來獲取所有的攔截器矢渊。
文件處理的入口方法
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (CollectionUtils.isNotEmpty(annotations)) {
//獲取所有被Interceptor注解的element
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Interceptor.class);
try {
//生成代碼
parseInterceptors(elements);
} catch (Exception e) {
logger.error(e);
}
return true;
}
return false;
}
根據(jù)Interceptor注解生成代碼
private void parseInterceptors(Set<? extends Element> elements) throws IOException {
if (CollectionUtils.isNotEmpty(elements)) {
logger.info(">>> Found interceptors, size is " + elements.size() + " <<<");
// Verify and cache, sort incidentally.
for (Element element : elements) {
//檢查攔截器,必須實(shí)現(xiàn)IInterceptor接口并且使用Interceptor注解
if (verify(element)) { // Check the interceptor meta
logger.info("A interceptor verify over, its " + element.asType());
Interceptor interceptor = element.getAnnotation(Interceptor.class);
Element lastInterceptor = interceptors.get(interceptor.priority());
//不允許多個(gè)攔截器使用同一個(gè)優(yōu)先級(jí)
if (null != lastInterceptor) { // Added, throw exceptions
throw new IllegalArgumentException(
String.format(Locale.getDefault(), "More than one interceptors use same priority [%d], They are [%s] and [%s].",
interceptor.priority(),
lastInterceptor.getSimpleName(),
element.getSimpleName())
);
}
//根據(jù)優(yōu)先級(jí)緩存
interceptors.put(interceptor.priority(), element);
} else {
logger.error("A interceptor verify failed, its " + element.asType());
}
}
// Interface of ARouter.
TypeElement type_ITollgate = elementUtil.getTypeElement(IINTERCEPTOR);
TypeElement type_ITollgateGroup = elementUtil.getTypeElement(IINTERCEPTOR_GROUP);
/**
* Build input type, format as :
*
* ```Map<Integer, Class<? extends ITollgate>>```
*/
ParameterizedTypeName inputMapTypeOfTollgate = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(Integer.class),
ParameterizedTypeName.get(
ClassName.get(Class.class),
WildcardTypeName.subtypeOf(ClassName.get(type_ITollgate))
)
);
// Build input param name.
//方法參數(shù) (Map<Integer, Class<? extends IInterceptor>> interceptors)
ParameterSpec tollgateParamSpec = ParameterSpec.builder(inputMapTypeOfTollgate, "interceptors").build();
// Build method : 'loadInto'
/**
* 創(chuàng)建方法
* Override
* public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors){}
*/
MethodSpec.Builder loadIntoMethodOfTollgateBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(tollgateParamSpec);
// Generate
/**
* 根據(jù)緩存生成代碼
* interceptors.put(priority,Test1Interceptor.class);
*/
if (null != interceptors && interceptors.size() > 0) {
// Build method body
for (Map.Entry<Integer, Element> entry : interceptors.entrySet()) {
loadIntoMethodOfTollgateBuilder.addStatement("interceptors.put(" + entry.getKey() + ", $T.class)",
ClassName.get((TypeElement) entry.getValue()));
}
}
// Write to disk(Write file even interceptors is empty.)
/**
* 生成類
* moduleName為每個(gè)module的build.gradle里配置的
* public class ARouter$$Interceptors$$moduleName implements IInterceptorGroup{
* public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceprors){
* interceptors.put(priority,Test1Interceptor.class);
* }
* }
*/
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(NAME_OF_INTERCEPTOR + SEPARATOR + moduleName)
.addModifiers(PUBLIC)
.addJavadoc(WARNING_TIPS)
.addMethod(loadIntoMethodOfTollgateBuilder.build())
.addSuperinterface(ClassName.get(type_ITollgateGroup))
.build()
).build().writeTo(mFiler);
logger.info(">>> Interceptor group write over. <<<");
}
}
源文件
@Interceptor(priority = 7)
public class Test1Interceptor implements IInterceptor {
Context mContext;
@Override
public void process(final Postcard postcard, final InterceptorCallback callback) {
}
@Override
public void init(Context context) {
}
}
生成文件
public class ARouter$$Interceptors$$app implements IInterceptorGroup {
@Override
public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
interceptors.put(7, Test1Interceptor.class);
}
}
RouteProcessor
RouteProcessor
類的作用是根據(jù)Route
注解的類來生成對(duì)應(yīng)的類枉证,這個(gè)類是對(duì)應(yīng)的路由表矮男,也就是Group對(duì)應(yīng)的path,path對(duì)應(yīng)的類的Class室谚。
文件處理的入口方法
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (CollectionUtils.isNotEmpty(annotations)) {
//所有被Route注解的Element
Set<? extends Element> routeElements = roundEnv.getElementsAnnotatedWith(Route.class);
try {
logger.info(">>> Found routes, start... <<<");
//根據(jù)Element生成代碼
this.parseRoutes(routeElements);
} catch (Exception e) {
logger.error(e);
}
return true;
}
return false;
}
根據(jù)Route生成代碼方法
private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
if (CollectionUtils.isNotEmpty(routeElements)) {
// Perpare the type an so on.
logger.info(">>> Found routes, size is " + routeElements.size() + " <<<");
rootMap.clear();
TypeMirror type_Activity = elements.getTypeElement(ACTIVITY).asType();
TypeMirror type_Service = elements.getTypeElement(SERVICE).asType();
TypeMirror fragmentTm = elements.getTypeElement(FRAGMENT).asType();
TypeMirror fragmentTmV4 = elements.getTypeElement(Consts.FRAGMENT_V4).asType();
// Interface of ARouter
TypeElement type_IRouteGroup = elements.getTypeElement(IROUTE_GROUP);
TypeElement type_IProviderGroup = elements.getTypeElement(IPROVIDER_GROUP);
ClassName routeMetaCn = ClassName.get(RouteMeta.class);
ClassName routeTypeCn = ClassName.get(RouteType.class);
/*
Build input type, format as :
```Map<String, Class<? extends IRouteGroup>>```
*/
ParameterizedTypeName inputMapTypeOfRoot = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ParameterizedTypeName.get(
ClassName.get(Class.class),
WildcardTypeName.subtypeOf(ClassName.get(type_IRouteGroup))
)
);
/*
```Map<String, RouteMeta>```
*/
ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ClassName.get(RouteMeta.class)
);
/*
Build input param name.
(Map<String, Class<? extends IRouteGroup>> routes)
*/
ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build();
//(Map<String, RouteMeta> atlas)
ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
//(Map<String, RouteMeta> providers)
ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build(); // Ps. its param type same as groupParamSpec!
/*
Build method : 'loadInto'
Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes);
*/
MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(rootParamSpec);
// Follow a sequence, find out metas of group first, generate java file, then statistics them as root.
for (Element element : routeElements) {
TypeMirror tm = element.asType();
Route route = element.getAnnotation(Route.class);
RouteMeta routeMete = null;
//如下代碼組裝RouterMete路由元數(shù)據(jù)
if (types.isSubtype(tm, type_Activity)) { // 1 // Activity
logger.info(">>> Found activity route: " + tm.toString() + " <<<");
// Get all fields annotation by @Autowired
Map<String, Integer> paramsType = new HashMap<>();
for (Element field : element.getEnclosedElements()) {
if (field.getKind().isField() && field.getAnnotation(Autowired.class) != null && !types.isSubtype(field.asType(), iProvider)) {
// It must be field, then it has annotation, but it not be provider.
//如果外圍類是Activity毡鉴,里面有被Autowired注解的字段且不是IProvider類型的,添加到Map中key為名字秒赤,value為字段類型的枚舉值猪瞬,具體查看typeUtils.typeExchange(field)方法
Autowired paramConfig = field.getAnnotation(Autowired.class);
paramsType.put(StringUtils.isEmpty(paramConfig.name()) ?
field.getSimpleName().toString() : paramConfig.name(), typeUtils.typeExchange(field));
}
}
routeMete = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
} else if (types.isSubtype(tm, iProvider)) { // IProvider
logger.info(">>> Found provider route: " + tm.toString() + " <<<");
routeMete = new RouteMeta(route, element, RouteType.PROVIDER, null);
} else if (types.isSubtype(tm, type_Service)) { // Service
logger.info(">>> Found service route: " + tm.toString() + " <<<");
routeMete = new RouteMeta(route, element, RouteType.parse(SERVICE), null);
} else if (types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {
logger.info(">>> Found fragment route: " + tm.toString() + " <<<");
routeMete = new RouteMeta(route, element, RouteType.parse(FRAGMENT), null);
}
categories(routeMete);
// if (StringUtils.isEmpty(moduleName)) { // Hasn't generate the module name.
// moduleName = ModuleUtils.generateModuleName(element, logger);
// }
}
/**
* Override
* public void loadInto(Map<String, RouteMeta> providers);
*/
MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(providerParamSpec);
// Start generate java source, structure is divided into upper and lower levels, used for demand initialization.
for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) {
String groupName = entry.getKey();
/**
* Override
* public void loadInto(Map<String, RouteMeta> atlas);
*/
MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(groupParamSpec);
// Build group method body
Set<RouteMeta> groupData = entry.getValue();
for (RouteMeta routeMeta : groupData) {
switch (routeMeta.getType()) {
case PROVIDER: // Need cache provider's super class
List<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces();
/**
* 如下代碼在方法public void loadInto(Map<String, RouteMeta> providers);中生成
* prvoiders.put("com.xxx.demo.HelloService",RouteMeta.build(RouteType.PROVIDER,HelloService.class,"/service/hello","service",null,priority,extra));
*/
for (TypeMirror tm : interfaces) {
if (types.isSameType(tm, iProvider)) { // Its implements iProvider interface himself.
// This interface extend the IProvider, so it can be used for mark provider
//tm 和 iProvider 相同
loadIntoMethodOfProviderBuilder.addStatement(
"providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
(routeMeta.getRawType()).toString(),
routeMetaCn,
routeTypeCn,
ClassName.get((TypeElement) routeMeta.getRawType()),
routeMeta.getPath(),
routeMeta.getGroup());
} else if (types.isSubtype(tm, iProvider)) {
// This interface extend the IProvider, so it can be used for mark provider
// tm 是 iProvider 的子類
loadIntoMethodOfProviderBuilder.addStatement(
"providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
// tm.toString().substring(tm.toString().lastIndexOf(".") + 1), // Spite unuseless name
tm.toString(), // So stupid, will duplicate only save class name.
routeMetaCn,
routeTypeCn,
ClassName.get((TypeElement) routeMeta.getRawType()),
routeMeta.getPath(),
routeMeta.getGroup());
}
}
break;
default:
break;
}
// Make map body for paramsType
/**
* 如下代碼只有Activity的時(shí)候才運(yùn)行,查看上面 1
* 生成代碼
* typeExchange,如上代碼入篮,為Autowired注解字段的類型
* put("Autowired.name",typeExchange);
*/
StringBuilder mapBodyBuilder = new StringBuilder();
Map<String, Integer> paramsType = routeMeta.getParamsType();
if (MapUtils.isNotEmpty(paramsType)) {
for (Map.Entry<String, Integer> types : paramsType.entrySet()) {
mapBodyBuilder.append("put(\"").append(types.getKey()).append("\", ").append(types.getValue()).append("); ");
}
}
String mapBody = mapBodyBuilder.toString();
/**
* 如下代碼在方法public void loadInto(Map<String, RouteMeta> atlas);中生成如下
* atlas.put("/service/hello",RouteMeta.build(RouteType.PROVIDER,HelloService.class,"/service/hello","service",null,priority,extra));
* 如果routeMeta.getType()為RouteType.ACTIVITY為下面這種形式
* atlas.put("/service/hello",RouteMeta.build(RouteType.PROVIDER,HelloService.class,"/service/hello","service",new java.util.HashMap<String, Integer>(){{put("Autowired.name",typeExchange);},priority,extra));
*/
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.get((TypeElement) routeMeta.getRawType()),
routeMeta.getPath().toLowerCase(),
routeMeta.getGroup().toLowerCase());
}
// Generate groups
/**
* 如下代碼生成類
* package com.alibaba.android.arouter.routes;
* public class ARouter$$Group$$groupName implements IRouteGroup{
* public void loadInto(Map<String, RouteMeta> atlas){
* atlas.put("/service/hello",RouteMeta.build(RouteType.PROVIDER,HelloService.class,"/service/hello","service",null,priority,extra));
* atlas.put("/service/hello",RouteMeta.build(RouteType.PROVIDER,HelloService.class,"/service/hello","service",new java.util.HashMap<String, Integer>(){{put("Autowired.name",typeExchange);},priority,extra));
* }
* }
*/
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);
}
/**
* 如下方法是在
* Override public void loadInto(Map<String, Class<? extends IRouteGroup>> routes);
* 方法中創(chuàng)建如下代碼
* routes.put(groupName, ARouter$$Group$$groupName.class)
*/
if (MapUtils.isNotEmpty(rootMap)) {
// Generate root meta by group name, it must be generated before root, then I can findout 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()));
}
}
// Wirte provider into disk
/**
* package com.alibaba.android.arouter.routes;
* public class ARouter$$Providers$$moudleName implements IProviderGroup{
* public void loadInto(Map<String, RouteMeta> providers){
* prvoiders.put("com.xxx.demo.HelloService",RouteMeta.build(RouteType.PROVIDER,HelloService.class,"/service/hello","service",null,priority,extra));
* }
* }
*/
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);
logger.info(">>> Generated provider map, name is " + providerMapFileName + " <<<");
// Write root meta into disk.
/**
* package com.alibaba.android.arouter.routes;
* public class ARouter&&Root$$moduleName implements IRouteRoot{
* Override
* public void loadInto(Map<String, Class<? extends IRouteGroup>> routes){
* routes.put(groupName, ARouter$$Group$$groupName.class)
* }
* }
*/
String rootFileName = NAME_OF_ROOT + SEPARATOR + moduleName;
JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
TypeSpec.classBuilder(rootFileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(elements.getTypeElement(ITROUTE_ROOT)))
.addModifiers(PUBLIC)
.addMethod(loadIntoMethodOfRootBuilder.build())
.build()
).build().writeTo(mFiler);
logger.info(">>> Generated root, name is " + rootFileName + " <<<");
}
}
生成文件
public class ARouter$$Root$$app implements IRouteRoot {
@Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("service", ARouter$$Group$$service.class);
routes.put("test", ARouter$$Group$$test.class);
}
}
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));
atlas.put("/service/json", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/service/json", "service", null, -1, -2147483648));
atlas.put("/service/single", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/service/single", "service", null, -1, -2147483648));
}
}
總結(jié):
上面對(duì)代碼生成部分做了詳細(xì)的代碼注釋陈瘦,主要用到的技術(shù)就是annotationProcessor
配合JavaPoet進(jìn)行代碼生成。
第二部分:路由加載
本地生成文件也進(jìn)行編譯打包潮售,那么程序是如何找到這些路由加載到內(nèi)存中呢痊项,我們直接找到'LogisticsCenter.public synchronized static void init(Context context, ThreadPoolExecutor tpe)'方法
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
mContext = context;
executor = tpe;
try {
// These class was generate by arouter-compiler.
//在所有的dex中根據(jù)package包名獲取arouter-compiler生成的class文件
List<String> classFileNames = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
//根據(jù)上面代碼過濾出的class路徑來講Route加載到內(nèi)存中
for (String className : classFileNames) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
// This one of root elements, load root.
/**
* 獲取arouter-compiler生成的ARouter$$Root$$moduleName類中的映射表
* 例如
* public class ARouter$$Root$$app implements IRouteRoot {
* @Override
* public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
* routes.put("service", ARouter$$Group$$service.class);
* routes.put("test", ARouter$$Group$$test.class);
* }
* }
*/
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
// Load interceptorMeta
/**
* 獲取arouter-compiler生成的ARouter$$Interceptors$$moduleName類的映射表
* 例如
* public class ARouter$$Interceptors$$app implements IInterceptorGroup {
* @Override
* public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
* interceptors.put(7, Test1Interceptor.class);
* }
* }
*/
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
// Load providerIndex
/**
* 獲取arouter-compiler生成的ARouter$$Providers$$moduleName類的映射表
* public class ARouter$$Providers$$app implements IProviderGroup {
* @Override
* public void loadInto(Map<String, RouteMeta> providers) {
* providers.put("com.alibaba.android.arouter.demo.testservice.SingleService", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/service/single", "service", null, -1, -2147483648));
* }
* }
*/
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
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() + "]");
}
}
在這個(gè)方法中難理解的地方是ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
方法,這個(gè)方法又調(diào)用List<String> getSourcePaths(Context context)
方法酥诽,如下兩個(gè)方法的代碼注釋:
/**
* 通過指定包名鞍泉,掃描包下面包含的所有的ClassName
*
* @param context U know
* @param packageName 包名
* @return 所有class的集合
*/
public static List<String> getFileNameByPackageName(Context context, String packageName) throws PackageManager.NameNotFoundException, IOException {
List<String> classNames = new ArrayList<>();
for (String path : getSourcePaths(context)) {
DexFile dexfile = null;
try {
if (path.endsWith(EXTRACTED_SUFFIX)) {
//NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache"
//提示權(quán)限錯(cuò)誤 /data/dalvik-cache 這個(gè)目錄
dexfile = DexFile.loadDex(path, path + ".tmp", 0);
} else {
//虛擬機(jī)將在目錄/data/dalvik-cache下生成對(duì)應(yīng)的文件名字并打開它
dexfile = new DexFile(path);
}
Enumeration<String> dexEntries = dexfile.entries();
while (dexEntries.hasMoreElements()) {
String className = dexEntries.nextElement();
if (className.contains(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) {
}
}
}
}
Log.d("ARouter", "Filter " + classNames.size() + " classes by packageName <" + packageName + ">");
return classNames;
}
List<String> getSourcePaths(Context context)
方法
public static List<String> getSourcePaths(Context context) throws PackageManager.NameNotFoundException, IOException {
ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0);
File sourceApk = new File(applicationInfo.sourceDir);
// Log.e(TAG,sourceApk.getAbsolutePath());
// Log.e(TAG,"12121212 : " + applicationInfo.sourceDir);
logger.info(TAG,"12121212 : " + applicationInfo.sourceDir);
List<String> sourcePaths = new ArrayList<>();
sourcePaths.add(applicationInfo.sourceDir); //add the default apk path
//the prefix of extracted file, ie: test.classes
String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT;
Log.e(TAG,extractedFilePrefix);
// 如果VM已經(jīng)支持了MultiDex,就不要去Secondary Folder加載 Classesx.zip了肮帐,那里已經(jīng)么有了
// 通過是否存在sp中的multidex.version是不準(zhǔn)確的咖驮,因?yàn)閺牡桶姹旧?jí)上來的用戶,是包含這個(gè)sp配置的
/**
* 如下這個(gè)方法判斷虛擬機(jī)是否支持multidex训枢,java.vm.version大于2.1的就是art虛擬機(jī)默認(rèn)支持multidex
* 如果虛擬機(jī)為art默認(rèn)支持multidex那么dex的路徑只有一個(gè)那就是applicationInfo.sourceDir例如: /data/app/com.alibaba.android.arouter.demo-wqT7WUHrcYy8UDBDFIXTmg==/base.apk
* 如果虛擬機(jī)為dalvik默認(rèn)不支持multidex托修,且對(duì)dex進(jìn)行分包處理那么加載/data/data/com.alibaba.android.arouter.demo/code_cache/secondray-dexes/
* 如果虛擬機(jī)為dalvik默認(rèn)不支持multidex,且由于代碼量太少?zèng)]有進(jìn)行分包處理那么加載applicationInfo.sourceDir路徑
*/
if (!isVMMultidexCapable()) {
//the total dex numbers
int totalDexNumber = getMultiDexPreferences(context).getInt(KEY_DEX_NUMBER, 1);
File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME);
//掃描/data/data/com.alibaba.android.arouter.demo/code_cache/secondray-dexes/ 路徑下所有的 xxx.apk.classes2.zip
for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++) {
//掃描/data/data/com.alibaba.android.arouter.demo/code_cache/secondray-dexes/ for each dex file, ie: test.classes2.zip, test.classes3.zip...
String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX;
File extractedFile = new File(dexDir, fileName);
if (extractedFile.isFile()) {
sourcePaths.add(extractedFile.getAbsolutePath());
//we ignore the verify zip part
} else {
throw new IOException("Missing extracted secondary dex file '" + extractedFile.getPath() + "'");
}
}
}
if (ARouter.debuggable()) { // Search instant run support only debuggable
sourcePaths.addAll(tryLoadInstantRunDexFile(applicationInfo));
}
return sourcePaths;
}
經(jīng)過'public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException'方法之后將arouter-compiler生成的代碼加載到內(nèi)存中提供程序使用,如下類:
class Warehouse {
// Cache route and metas
//加載ARouter$$Root$$moduleName類的映射表
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<>();
//加載ARouter$$Providers$$moduleName類的映射表
static Map<String, RouteMeta> providersIndex = new HashMap<>();
// Cache interceptor
//加載ARouter$$Interceptors$$moduleName類的映射表
static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
static List<IInterceptor> interceptors = new ArrayList<>();
}
如下兩張圖片圖一為art虛擬機(jī)編譯后獲取dex文件的目錄恒界,圖二為dalvik虛擬機(jī)編譯后獲取dex文件的目錄
總結(jié):
根據(jù)虛擬機(jī)是否默認(rèn)支持multidex睦刃,分別在不同的文件夾中掃描生成的zip或apk文件路徑;將路徑通過DexFile獲取所有的className仗处,通過指定的package來過濾出有用的className眯勾;在將過濾出來的className填充到Warehouse類中的緩存中,給程序提供使用婆誓。
第一部分:路由跳轉(zhuǎn)
路由跳轉(zhuǎn)方法調(diào)用棧
//ARouter類
ARouter.getInstance().build(BaseConstantDef.ROUTER_PATH_AC1).navigation();
//_ARouter類
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback);
//如上方法中調(diào)用
LogisticsCenter.completion(postcard);//拼裝Postcard類
//符合要求執(zhí)行攔截器
interceptorService.doInterceptions();
//最后調(diào)用真正的跳轉(zhuǎn)方法
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback)
上面是路由跳轉(zhuǎn)的方法調(diào)用棧,下面是代碼解析:
LogisticsCenter.completion(postcard)方法
public synchronized static void completion(Postcard postcard) {
if (null == postcard) {
throw new NoRouteFoundException(TAG + "No postcard!");
}
/**
* 這部分代碼
* 1. path在Warehouse.routes緩存中沒有也颤,進(jìn)入這個(gè)分支
* 2. 根據(jù)group在Warehouse.groupsIndex中取出對(duì)應(yīng)的IRouterGroup這個(gè)接口中存放的就是這個(gè)group中所有的path
* 3. 取出之后將這個(gè)group下的所有path緩存到Warehouse.routes中洋幻,key為path,value為RouteMeta
* 4. 緩存成功刪除Warehouse.groupsIndex中對(duì)應(yīng)的group數(shù)據(jù)
* 5. 重復(fù)調(diào)用completion方法翅娶,根據(jù)path命中緩存取出RouteMeta
* 6. 根據(jù)RouteMeta來組裝Postcard
* 7. 解析Uri中的參數(shù)文留,拼裝成Android的bundle傳輸
* 8. routeMeta.getType()如果等于provider好唯,那么從Warehouse.providers中根據(jù)routeMeta.getDestination()取出Provider
* 9. 如果取出為空那么創(chuàng)建,并且緩存到Warehouse.providers中燥翅,key為provider的class骑篙,value為provider的實(shí)例對(duì)象
* 10. 如果是provider 設(shè)置postcard.greenChannel() 跳過攔截器
* 11. 從第8點(diǎn)開始 routeMeta.getType()如果等于fragment,則直接設(shè)置postcard.greenChannel() 跳過攔截器
*/
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath()); // 1
if (null == routeMeta) { // Maybe its does't exist, or didn't load.
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); // 2 Load route meta.
if (null == groupMeta) {
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
// Load route and cache it into memory, then delete from metas.
try {
if (ARouter.debuggable()) {
logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
}
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance(); // 3
iGroupInstance.loadInto(Warehouse.routes);
Warehouse.groupsIndex.remove(postcard.getGroup()); // 4
if (ARouter.debuggable()) {
logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] has already been loaded, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
}
} catch (Exception e) {
throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
}
completion(postcard); // 5 Reload
}
} else {
// 6
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
// 7
Uri rawUri = postcard.getUri();
if (null != rawUri) { // Try to set params into bundle.
Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
Map<String, Integer> paramsType = routeMeta.getParamsType();
if (MapUtils.isNotEmpty(paramsType)) {
// Set value by its type, just for params which annotation by @Param
for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
setValue(postcard,
params.getValue(),
params.getKey(),
resultMap.get(params.getKey()));
}
// Save params name which need autoinject.
postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
}
// Save raw uri
postcard.withString(ARouter.RAW_URI, rawUri.toString());
}
switch (routeMeta.getType()) {
case PROVIDER: // 8 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 {
// 9
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(); // 10 Provider should skip all of interceptors
break;
case FRAGMENT:
postcard.greenChannel(); // Fragment needn't interceptors
default:
break;
}
}
}
interceptorService.doInterceptions()攔截器查看InterceptorServiceImpl源碼:
@Override
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {
checkInterceptorsInitStatus();
if (!interceptorHasInit) {
callback.onInterrupt(new HandlerException("Interceptors initialization takes too much time."));
return;
}
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
//這個(gè)同步工具類是為了防止在攔截器中不回掉callback方法森书,或者攔截器中有線程延遲回調(diào)callback方法
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
//遞歸執(zhí)行所有攔截器
_excute(0, interceptorCounter, postcard);
//這段代碼是等待攔截器中線程執(zhí)行完成回調(diào)callback來清除CountDownLatch標(biāo)志靶端,但是他有個(gè)超時(shí)時(shí)間
interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
if (interceptorCounter.getCount() > 0) { // Cancel the navigation this time, if it hasn't return anythings.
callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
} else if (null != postcard.getTag()) { // Maybe some exception in the tag.
callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
} else {
callback.onContinue(postcard);
}
} catch (Exception e) {
callback.onInterrupt(e);
}
}
});
} else {
callback.onContinue(postcard);
}
}
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback)
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
try {
//拼裝Postcard類
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
logger.warning(Consts.TAG, ex.getMessage());
if (debuggable()) { // Show friendly tips for user.
Toast.makeText(mContext, "There's no route matched!\n" +
" Path = [" + postcard.getPath() + "]\n" +
" Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();
}
if (null != callback) {
callback.onLost(postcard);
} else { // No callback for this invoke, then we use the global degrade service.
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
return null;
}
if (null != callback) {
callback.onFound(postcard);
}
if (!postcard.isGreenChannel()) { // It must be run in async thread, maybe interceptor cost too mush time made ANR.
/**
*除了provider和fragment都需要走攔截器,然后在發(fā)送navigation
* 請(qǐng)查看InterceptorServiceImpl源碼異步執(zhí)行所有攔截器凛膏,并且通過CountDownLatch來進(jìn)行同步
*/
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
/**
* Continue process
*
* @param postcard route meta
*/
@Override
public void onContinue(Postcard postcard) {
//攔截器都正確返回
_navigation(context, postcard, requestCode, callback);
}
/**
* Interrupt process, pipeline will be destory when this method called.
*
* @param exception Reson of interrupt.
*/
@Override
public void onInterrupt(Throwable exception) {
if (null != callback) {
callback.onInterrupt(postcard);
}
logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());
}
});
} else {
return _navigation(context, postcard, requestCode, callback);
}
return null;
}
參考文獻(xiàn):
http://www.importnew.com/15731.html
https://it.baiked.com/jdkapi1.8/javax/lang/model/element/TypeElement.html