枫叶「零碎记录」

ARouter源码分析

字数统计: 4.7k阅读时长: 24 min
2017/11/06 Share

分析需要储备以下知识点:

  • Java注解知识
  • Java反射知识
  • javapoet库(在注释里也有简单分析)
  • auto-service库

下面分析的时候会把各位看官当做已经掌握了以上知识点哈!

ARouter包含3个核心模块.jpg

ARouter包含3个核心模块

  1. arouter-annotation 注解的声明和信息存储类的模块
  2. arouter-compiler 编译期解析注解信息并生成相应类以便进行注入的模块
  3. arouter-api 核心调用Api功能的模块

1.模块arouter-annotation分析

  • 这个注解用于路由传递过来的对象自动进行注入值

参数注入的注解

  • 这个拦截器注解主要是用来声明和确定拦截器优先级

拦截器

Param注解

  • Route注解是用到最多的,用来声明路由的路径和分组(分组这块后面会详细讲解,因为分组这块用到懒加载的形式来提高性能)

Route注解

RouteType解析用的

RouteMeta放数据用的后面Postcard会继承

总结:这个模块主要还是用来声明注解的参数和compiler搭配使用这样分开,让结构更加清晰。

2.模块arouter-compiler分析

1
2
3
4
在这个模块中引用了一下两个核心库
compile 'com.google.auto.service:auto-service:1.0-rc2' //auto-service 主要用于注解 Processor,对其生成 META-INF 配置信息。
compile 'com.squareup:javapoet:1.7.0' // Javapoet是square一个工具,提供了各种 API 让你用各种姿势去生成 Java 代码文件,避免了徒手拼接字符串的尴尬。

AutowiredProcessor分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
package com.alibaba.android.arouter.compiler.processor;
import com.alibaba.android.arouter.compiler.utils.Consts;
import com.alibaba.android.arouter.compiler.utils.Logger;
import com.alibaba.android.arouter.compiler.utils.TypeUtils;
import com.alibaba.android.arouter.facade.annotation.Autowired;
import com.alibaba.android.arouter.facade.enums.TypeKind;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import static com.alibaba.android.arouter.compiler.utils.Consts.ANNOTATION_TYPE_AUTOWIRED;
import static com.alibaba.android.arouter.compiler.utils.Consts.ISYRINGE;
import static com.alibaba.android.arouter.compiler.utils.Consts.JSON_SERVICE;
import static com.alibaba.android.arouter.compiler.utils.Consts.KEY_MODULE_NAME;
import static com.alibaba.android.arouter.compiler.utils.Consts.METHOD_INJECT;
import static com.alibaba.android.arouter.compiler.utils.Consts.NAME_OF_AUTOWIRED;
import static com.alibaba.android.arouter.compiler.utils.Consts.WARNING_TIPS;
import static javax.lang.model.element.Modifier.PUBLIC;
/**
* Processor used to create autowired helper
*
* @author zhilong <a href="mailto:zhilong.lzl@alibaba-inc.com">Contact me.</a>
* @version 1.0
* @since 2017/2/20 下午5:56
*/
@AutoService(Processor.class)//用 @AutoService 来注解这个处理器,可以自动生成配置信息。
@SupportedOptions(KEY_MODULE_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({ANNOTATION_TYPE_AUTOWIRED})
public class AutowiredProcessor extends AbstractProcessor {
private Filer mFiler; //文件相关的辅助类
private Logger logger;
private Types types; //类型相关的辅助类
private TypeUtils typeUtils;
private Elements elements; //元素相关的辅助类
private Map<TypeElement, List<Element>> parentAndChild = new HashMap<>(); // 包含注解字段的Map集合 // Contain field need autowired and his super class.
private static final ClassName ARouterClass = ClassName.get("com.alibaba.android.arouter.launcher", "ARouter");
private static final ClassName AndroidLog = ClassName.get("android.util", "Log");
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
mFiler = processingEnv.getFiler(); // Generate class.
types = processingEnv.getTypeUtils(); // Get type utils.
elements = processingEnv.getElementUtils(); // Get class meta.
typeUtils = new TypeUtils(types, elements);
logger = new Logger(processingEnv.getMessager()); // Package the log utils.
logger.info(">>> AutowiredProcessor init. <<<");
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (CollectionUtils.isNotEmpty(set)) {
try {
logger.info(">>> Found autowired field, start... <<<");
//传入被Autowire注解修饰的集合并且执行分类填充进parentAndChild的Map集合
categories(roundEnvironment.getElementsAnnotatedWith(Autowired.class));
//执行解析
generateHelper();
} catch (Exception e) {
logger.error(e);
}
return true;
}
return false;
}
private void generateHelper() throws IOException, IllegalAccessException {
TypeElement type_ISyringe = elements.getTypeElement(ISYRINGE); //获取注入对象的元素类
TypeElement type_JsonService = elements.getTypeElement(JSON_SERVICE);// 获取JsonService元素类
TypeMirror iProvider = elements.getTypeElement(Consts.IPROVIDER).asType(); //获取IProvider类对象
TypeMirror activityTm = elements.getTypeElement(Consts.ACTIVITY).asType(); //获取activity类对象
TypeMirror fragmentTm = elements.getTypeElement(Consts.FRAGMENT).asType(); //获取fragment类对象
TypeMirror fragmentTmV4 = elements.getTypeElement(Consts.FRAGMENT_V4).asType(); //获取fragment的v4版本的类对象
// Build input param name.
ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build(); //生成方法的参数 ***(Object target)
if (MapUtils.isNotEmpty(parentAndChild)) { //解析parentAndChild
for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) { // 被autowire注解的循环对象
// Build method : 'inject'
MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder(METHOD_INJECT)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(objectParamSpec);
//生成方法injtct 所以和上面联合在一块就是生成了@override public void inject(Object target)
TypeElement parent = entry.getKey();
List<Element> childs = entry.getValue();
String qualifiedName = parent.getQualifiedName().toString();//整个类名
String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf("."));//截取包名
String fileName = parent.getSimpleName() + NAME_OF_AUTOWIRED;//文件名
logger.info(">>> Start process " + childs.size() + " field in " + parent.getSimpleName() + " ... <<<");
// 生成类 类名是 **$$**$***实现ISyringe接口并且是public的类
TypeSpec.Builder helper = TypeSpec.classBuilder(fileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(type_ISyringe))
.addModifiers(PUBLIC);
// 生成一个私有的全局对象serializationService
FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService", Modifier.PRIVATE).build();
helper.addField(jsonServiceField);
// 在方法体内加入指定的语句执行
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的子类
if ("".equals(fieldConfig.name())) { // User has not set service path, then use byType.
//默认通过类解析
// Getter
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = $T.getInstance().navigation($T.class)",
ARouterClass,
ClassName.get(element.asType())
);
} else { // use byName //如果指定了Autowired的name的话 则用name进行解析
// Getter
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = ($T)$T.getInstance().build($S).navigation();",
ClassName.get(element.asType()),
ARouterClass,
fieldConfig.name()
);
}
// Validater 校验
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 originalValue = "substitute." + fieldName;
String statement = "substitute." + fieldName + " = substitute.";
boolean isActivity = false;
if (types.isSubtype(parent.asType(), activityTm)) { // Activity, then use getIntent() 如果是activity则通过getIntent注入
isActivity = true;
statement += "getIntent().";
} else if (types.isSubtype(parent.asType(), fragmentTm) || types.isSubtype(parent.asType(), fragmentTmV4)) { // Fragment, then use getArguments() 如果是fragment则通过getArguements进行注入
statement += "getArguments().";
} else {//其他方式暂不支持
throw new IllegalAccessException("The field [" + fieldName + "] need autowired from intent, its parent must be activity or fragment!");
}
//判断类型进行相应的转换生成代码
statement = buildStatement(originalValue, statement, typeUtils.typeExchange(element), isActivity);
// 生成servicejson解析的服务循环解析生成代码
if (statement.startsWith("serializationService.")) { // Not mortals
injectMethodBuilder.beginControlFlow("if (null != serializationService)");
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = " + statement,
(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 {
//在方法体内加入代码
injectMethodBuilder.addStatement(statement, StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name());
}
// Validator 校验支持解析的类型为空则做记录
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. <<<");
}
}
private String buildStatement(String originalValue, String statement, int type, boolean isActivity) {
if (type == TypeKind.BOOLEAN.ordinal()) {
statement += (isActivity ? ("getBooleanExtra($S, " + originalValue + ")") : ("getBoolean($S)"));
} else if (type == TypeKind.BYTE.ordinal()) {
statement += (isActivity ? ("getByteExtra($S, " + originalValue + "") : ("getByte($S)"));
} else if (type == TypeKind.SHORT.ordinal()) {
statement += (isActivity ? ("getShortExtra($S, " + originalValue + ")") : ("getShort($S)"));
} else if (type == TypeKind.INT.ordinal()) {
statement += (isActivity ? ("getIntExtra($S, " + originalValue + ")") : ("getInt($S)"));
} else if (type == TypeKind.LONG.ordinal()) {
statement += (isActivity ? ("getLongExtra($S, " + originalValue + ")") : ("getLong($S)"));
} else if (type == TypeKind.CHAR.ordinal()) {
statement += (isActivity ? ("getCharExtra($S, " + originalValue + ")") : ("getChar($S)"));
} else if (type == TypeKind.FLOAT.ordinal()) {
statement += (isActivity ? ("getFloatExtra($S, " + originalValue + ")") : ("getFloat($S)"));
} else if (type == TypeKind.DOUBLE.ordinal()) {
statement += (isActivity ? ("getDoubleExtra($S, " + originalValue + ")") : ("getDouble($S)"));
} else if (type == TypeKind.STRING.ordinal()) {
statement += (isActivity ? ("getStringExtra($S)") : ("getString($S)"));
} else if (type == TypeKind.PARCELABLE.ordinal()) {
statement += (isActivity ? ("getParcelableExtra($S)") : ("getParcelable($S)"));
} else if (type == TypeKind.OBJECT.ordinal()) {
statement = "serializationService.parseObject(substitute." + (isActivity ? "getIntent()." : "getArguments().") + (isActivity ? "getStringExtra($S)" : "getString($S)") + ", new com.alibaba.android.arouter.facade.model.TypeWrapper<$T>(){}.getType())";
}
return statement;
}
/**
* Categories field, find his papa.
*
* @param elements Field need autowired
*/
private void categories(Set<? extends Element> elements) throws IllegalAccessException {
if (CollectionUtils.isNotEmpty(elements)) {//判断注解集合是不是为空
for (Element element : elements) {//循环解析
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();// 获取父元素
if (element.getModifiers().contains(Modifier.PRIVATE)) {// 检验是否注解的对象不能被private修饰
throw new IllegalAccessException("The inject fields CAN NOT BE 'private'!!! please check field ["
+ element.getSimpleName() + "] in class [" + enclosingElement.getQualifiedName() + "]");
}
if (parentAndChild.containsKey(enclosingElement)) { // Has categries
parentAndChild.get(enclosingElement).add(element);
} else {//第1次进入会生成列表并且组装到parentAndChild的map中
List<Element> childs = new ArrayList<>();
childs.add(element);
parentAndChild.put(enclosingElement, childs);
}
}
logger.info("categories finished.");
}
}
}

都是通过解析Element对象的注解的参数来进行编写相应的Java类
下图就是上面AutowiredProcessor通过解析生成的类

自动生成的注入类

下图是拦截器的Processor类和上面一样也会生成相应的拦截类具体的代码都很相似就不贴分析的代码啦

拦截器Processor

贴上拦截器注解后编译器生成的类

自动生成的拦截类

在Route的Processor中验证路径的代码和上面是很类似的就不一一分析的需要注意点校验和分类

路由校验

路由分类排序

总结:以上的类稍微了解就好,因为使用到的就是将注解解析自动生成响应的类方便Api核心去调用将整个框架联动起来

3.模块arouter-api分析

在外部使用的时候调用的Api是ARouter,但是它是使用代理模式,实际上的操作是_ARouter类进行调用。

我们从init方法开始解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Init, it must be call before used router.
*/
public static void init(Application application) {
if (!hasInit) {
logger = _ARouter.logger; //需要初始化出_ARouter的日志类 因为内部和外部都会调用所以一定要先调init
_ARouter.logger.info(Consts.TAG, "ARouter init start.");
hasInit = _ARouter.init(application);//真正的初始化ARouter核心 里面调用了LogisticsCenter.init(mContext, executor);内部创建了一个线程池
if (hasInit) {
_ARouter.afterInit();//初始化完成之后开始处理拦截器
}
_ARouter.logger.info(Consts.TAG, "ARouter init over.");
}
}

LogisticCenter的初始化核心就是讲自定义生成的类进行调用loadInto然后缓存近Warehouse仓库中以便快速调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
* 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();
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 generate by arouter-compiler.
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);//搜索routerMap
if (!routerMap.isEmpty()) {
context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();// 将搜索到的map保存到sp中
}
} 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();
for (String className : routerMap) {//通过反射初始化自动生成的类并且进行调用loadInto方法将数据缓存到Warehouse的仓库中
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() + "]");
}
}

在我们所有调用ARouter.getInstance().build(-).navigation()都会经来进行组装Postcard和completion方法通知组装完成,所以我们再来看一下postcard是个什么鬼

Postcard类

看了一下就是继承了RouteMeta并且多了一些参数,换句话说就是在View层可以多自定义一些动画和参数传递的方式

那么继续看completion方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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.
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); // 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(); //对路由的路径进行分组
iGroupInstance.loadInto(Warehouse.routes);
Warehouse.groupsIndex.remove(postcard.getGroup());
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); // Reload //分组完毕后进行重新加载 也就是会执行到下面else段
}
} else {
// 将所有手机到的目标信息都取出来封装进postcard
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
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 auto inject.
postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
}
// Save raw uri
postcard.withString(ARouter.RAW_URI, rawUri.toString());
}
/**
* 如果是Iprovider服务类和fragment则跳过所有拦截器
*/
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;
case FRAGMENT:
postcard.greenChannel(); // Fragment needn't interceptors
default:
break;
}
}
}

核心的封装流程讲完了咱们开始看路由的跳转和拦截:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
@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() { //使用线程池并且利用CountDownLatch来处理线程同步问题进行一个个拦截器的兰姐
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
_excute(0, interceptorCounter, postcard);
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);
}
}
/**
* Excute interceptor
*
* @param index current interceptor index
* @param counter interceptor counter
* @param postcard routeMeta
*/
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() {
@Override
public void onContinue(Postcard postcard) {
// Last interceptor excute over with no exception.
counter.countDown();
// 回调自身将所有拦截器执行一边
_excute(index + 1, counter, postcard); // When counter is down, it will be execute continue ,but index bigger than interceptors size, then U know.
}
@Override
public void onInterrupt(Throwable exception) {
// Last interceptor excute over with fatal exception.
postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage()); // save the exception message for backup.
//如果已经被拦截则取消同步状态
counter.cancel();
// Be attention, maybe the thread in callback has been changed,
// then the catch block(L207) will be invalid.
// The worst is the thread changed to main thread, then the app will be crash, if you throw this exception!
// if (!Looper.getMainLooper().equals(Looper.myLooper())) { // You shouldn't throw the exception if the thread is main thread.
// throw new HandlerException(exception.getMessage());
// }
}
});
}
}

看到以上代码知道他们是利用线程池加上CountLatchDown的方式来进行线程空值同步并且调用_excute进行回调来一步步拿出拦截器来调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
* Use router navigation.
*
* @param context Activity or null.
* @param postcard Route metas
* @param requestCode RequestCode
* @param callback cb
*/
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
try {
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. //判断当前调用是不是走『绿色通道』跳过所有拦截器
//一定要调用一下两个方式之一才能继续执行路径否则返回为空
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;
}

跳转返回对象的处理

到这里核心的流程基本全部讲完了,因此可以看到拦截都是进行全局的拦截,但是他们通过注解的extra值进行处理来分类拦截的过程通过优先级排序拦截。更多的细节大家可以下载源码仔细研究,希望本文对大家有帮助,如有错误之处,涵请指出,多多指教,感激不尽。

有问题可以来我博客或者简书反馈

CATALOG
  1. 1. 1.模块arouter-annotation分析
  2. 2. 2.模块arouter-compiler分析
  3. 3. 3.模块arouter-api分析