Android 开源库分析——ARouter使用及源码解析

本文链接:https://rainmonth.github.io/posts/A191110.html

摘要

最近在学习项目组件化时用到了ARouter,本文先介绍ARouter的特性及基本使用,然后从源码的角度分析ARouter的实现原理。
注意本文分析的版本分别为:

  • arouter-api,1.5.0;
  • arouter-compiler,1.2.2

特性

ARouter官方说是帮助App进行组件化改造的框架——支持模块间的路由、通信、解耦。其具有以下特点(内容来自官方文档):

  • 支持直接解析标准URL进行跳转,并自动注入参数到目标页面中,如arouter://m.aliyun.com/test/activity3?name=alex&age=18&boy=true&high=180
  • 支持多模块工程使用
  • 支持添加多个拦截器,自定义拦截顺序
  • 支持依赖注入,可单独作为依赖注入框架使用
  • 支持InstantRun
  • 支持MultiDex(Google方案)
  • 映射关系按组分类、多级管理,按需初始化
  • 支持用户指定全局降级与局部降级策略
  • 页面、拦截器、服务等组件均自动注册到框架
  • 支持多种方式配置转场动画
  • 支持获取Fragment
  • 完全支持Kotlin以及混编(配置见文末 其他#5)
  • 支持第三方 App 加固(使用 arouter-register 实现自动注册)
  • 支持生成路由文档
  • 提供 IDE 插件便捷的关联路径和目标类

基本使用

源码分析

arouter-api

提供ARouter的API实现,如我们使用ARouter的入口ARouter.getInstance()及常用的一些调整配置方法,都定义在这。
arouter-api的结构

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
com.alibaba.android.arouter.api
├── base
│   └── UniqueKeyTreeMap.java # key 唯一的红黑树
├── core #
│   ├── AutowiredLifecycleCallback.java
│   ├── AutowiredServiceImpl.java # AutowiredService的具体实现
│   ├── InstrumentationHook.java # Hook Instrumentation的newActivity方法的
│   ├── InterceptorServiceImpl.java
│   ├── LogisticsCenter.java # 核心逻辑实现,生成路由map,并现将路由信息保存在内存中(Warehouse中)
│   └── Warehouse.java # 提供存储服务,用来存储路由数据、拦截器数据等
├── exception # 异常定义
│   ├── HandlerException.java
│   ├── InitException.java
│   └── NoRouteFoundException.java
├── facade
│   ├── Postcard.java # 包含路由路劲图的容器(ARouter功能实现的基础),继承自RouteMeta,包含各种参数的定义及获取方法
│   ├── callback # 回调定义
│   │   ├── InterceptorCallback.java # 拦截回调定义
│   │   ├── NavCallback.java # 导航回调定义默认实现
│   │   └── NavigationCallback.java # 导航跳转回调定义
│   ├── service # 服务定义
│   │   ├── AutowiredService.java # 自动注入接口定义
│   │   ├── ClassLoaderService.java # 类加载接口定义
│   │   ├── DegradeService.java # 降级接口
│   │   ├── InterceptorService.java # 拦截接口定义
│   │   ├── PathReplaceService.java # 路由路径预处理接口(普通的String 路径和Uri路径)
│   │   ├── PretreatmentService.java # 导航预处理服务(用来检查是否需要导航跳转)
│   │   └── SerializationService.java # Json解析服务
│   └── template # 模板包(定义了ARouter生成的文件格式)
│   ├── IInterceptor.java # 跳转拦截服务(针对单个跳转)
│   ├── IInterceptorGroup.java # 跳转拦截服务(针对某个Group,即拦截符合条件的Group内的所有跳转)
│   ├── ILogger.java # 日志服务
│   ├── IPolicy.java #
│   ├── IProvider.java # 所有服务的父接口,提供初始化的init方法
│   ├── IProviderGroup.java #
│   ├── IRouteGroup.java #
│   ├── IRouteRoot.java # ARouter$$Root模板
│   └── ISyringe.java # Autowired注解模板
├── launcher # ARouter的入口
│   ├── ARouter.java # 获取ARouter的实例,采用单例实现,内部持有_ARouter实例,所有功能真正的实现都交给_ARouter
│   └── _ARouter.java # _ARouter的真正实现
├── thread # ARouter使用的线程模型
│   ├── CancelableCountDownLatch.java # 在拦截器的相关实现时有用到
│   ├── DefaultPoolExecutor.java # 默认线程池
│   └── DefaultThreadFactory.java # 默认线程池工厂类
└── utils # 相关工具类
├── ClassUtils.java # 提供获取类名、dex file path等方法
├── Consts.java # 相关常量
├── DefaultLogger.java # 默认日志支持
├── MapUtils.java
├── PackageUtils.java
└── TextUtils.java

这里着重看下LogisticsCenter.java 中的init方法,因为在ARouter.getInstance().init()最终会走到这个方法:
_Arouter.java的init方法

1
2
3
4
5
6
7
8
9
10
11
protected static synchronized boolean init(Application application) {
mContext = application;
// 将默认的线程池传递给Logistics,以方便后面InterceptorService实现拦截时调用
LogisticsCenter.init(mContext, executor);
logger.info(Consts.TAG, "ARouter init success!");
hasInit = true;
// 用来切换到主线程的Handler
mHandler = new Handler(Looper.getMainLooper());

return true;
}

LogisticsCenter.java的init方法

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
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
mContext = context;
executor = tpe;

try {
long startInit = System.currentTimeMillis();
// 加载路由图,优先采用插件加载
loadRouterMap();
if (registerByPlugin) {
logger.info(TAG, "Load router map by arouter-auto-register plugin.");
} else {
Set<String> routerMap;

// 调试模式下或者新版本发布时,会重新生成路由图
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
// 获取ARouter编译器生成的类名,编译器即ARouter-compiler
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
if (!routerMap.isEmpty()) {
// 本地化路由图
context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
}
// 更新路由版本号
PackageUtils.updateVersion(context); // Save new version name when router map update finishes.
} else {
logger.info(TAG, "Load router map from cache.");
routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
}

logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
startInit = System.currentTimeMillis();

// 解析ARouter编译器生成的类并将其加入Warehouse(即存在本地内存中
for (String className : routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
// This one of root elements, load root.
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
// Load interceptorMeta
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
// Load providerIndex
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
}

// 输出必要的日志信息
logger.info(TAG, "Load root element finished, cost " + (System.currentTimeMillis() - startInit) + " ms.");

if (Warehouse.groupsIndex.size() == 0) {
logger.error(TAG, "No mapping files were found, check your configuration please!");
}

if (ARouter.debuggable()) {
logger.debug(TAG, String.format(Locale.getDefault(), "LogisticsCenter has already been loaded, GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]", Warehouse.groupsIndex.size(), Warehouse.interceptorsIndex.size(), Warehouse.providersIndex.size()));
}
} catch (Exception e) {
throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
}
}

上面方法其实等同于Logistics.register方法,只不过register方法是由插件调用的,看看register方法的实现:

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
private static void register(String className) {
if (!TextUtils.isEmpty(className)) {
try {
Class<?> clazz = Class.forName(className);
Object obj = clazz.getConstructor().newInstance();
if (obj instanceof IRouteRoot) {
registerRouteRoot((IRouteRoot) obj);
} else if (obj instanceof IProviderGroup) {
registerProvider((IProviderGroup) obj);
} else if (obj instanceof IInterceptorGroup) {
registerInterceptor((IInterceptorGroup) obj);
} else {
logger.info(TAG, "register failed, class name: " + className
+ " should implements one of IRouteRoot/IProviderGroup/IInterceptorGroup.");
}
} catch (Exception e) {
logger.error(TAG,"register class error:" + className);
}
}
}

/**
* 供arouter-auto-register 插件调用的方法
*/
private static void registerRouteRoot(IRouteRoot routeRoot) {
markRegisteredByPlugin();
if (routeRoot != null) {
routeRoot.loadInto(Warehouse.groupsIndex);
}
}

/**
* 供arouter-auto-register 插件调用的方法
*/
private static void registerInterceptor(IInterceptorGroup interceptorGroup) {
markRegisteredByPlugin();
if (interceptorGroup != null) {
interceptorGroup.loadInto(Warehouse.interceptorsIndex);
}
}

/**
* 供arouter-auto-register 插件调用的方法
*/
private static void registerProvider(IProviderGroup providerGroup) {
markRegisteredByPlugin();
if (providerGroup != null) {
providerGroup.loadInto(Warehouse.providersIndex);
}
}

方法比较简单,至于到底注册了什么,将在后面分析ARouter-compiler时具体分析。

在使用ARouter时,最终都会调用navigation()方法,而这个navigation有两种类型的实现:

  • 不带页面跳转的
  • 带页面跳转的

先看看不带页面跳转的,其方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 这个方法最终户返回一个实现了IProvider的服务的实例,获取该实例后可以调用该服务中定义的方法(服务中使用context对象也是可以的,因为IProvider提供了Context对象的初始化方法。
protected <T> T navigation(Class<? extends T> service) {
try {
// 创建Postcard对象
Postcard postcard = LogisticsCenter.buildProvider(service.getName());

if (null == postcard) {
// 创建Postcard对象(兼容处理)
postcard = LogisticsCenter.buildProvider(service.getSimpleName());
}

if (null == postcard) {
return null;
}
// 完善postcard对象的信息
LogisticsCenter.completion(postcard);
// 返回IProvider实例
return (T) postcard.getProvider();
} catch (NoRouteFoundException ex) {
logger.warning(Consts.TAG, ex.getMessage());
return null;
}
}

在看看带页面跳转的,其方法如下:

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
// 带页面跳转的navigation
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
// 这里可以对postcard进行一个预处理,如果不通过就不跳转(目前获取到的pretreatmentService为空)
PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
// 需要预处理,但预处理失败,则返回null,结束跳转
return null;
}

try {
// 完善Postcard信息
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
logger.warning(Consts.TAG, ex.getMessage());

if (debuggable()) {
// 调试的情况下通知用户路由异常了
runInMainThread(new Runnable() {
@Override
public void run() {
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 {
// 没有回到时如果降级策略不为空,则采用降级策略来处理
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
// 终端跳转
return null;
}

// 处理找到路由的情况
if (null != callback) {
// 有回调的话先调用通知找到路由了
callback.onFound(postcard);
}

// 非绿色通道,调用ARouter默认的拦截器服务进行拦截
if (!postcard.isGreenChannel()) { // 拦截需要在异步线程中进行,避免拦截时间过长导致ANR
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
/**
* 处理继续跳转的逻辑(不符合拦截条件)
*/
@Override
public void onContinue(Postcard postcard) {
_navigation(context, postcard, requestCode, callback);
}

/**
* 处理拦截跳转的逻辑(符合拦截条件)
*/
@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;
}

// 真正跳转的实现
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = null == context ? mContext : context;
// 根据跳转类型进行跳转参数的构建
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 (-1 != flags) {
intent.setFlags(flags);
} else if (!(currentContext instanceof Activity)) { // Non activity, need less one flag.
// 如果不是由Activity发起的跳转,需要添加FLAG_ACTIVITY_NEW_TASK这个Flag
intent.setFlags(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);
}
});

break;
case PROVIDER:
return postcard.getProvider();
case BOARDCAST:
case CONTENT_PROVIDER:
case FRAGMENT:
Class fragmentMeta = postcard.getDestination();
try {
Object instance = fragmentMeta.getConstructor().newInstance();
if (instance instanceof Fragment) {
((Fragment) instance).setArguments(postcard.getExtras());
} else if (instance instanceof android.support.v4.app.Fragment) {
((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());
}

return instance;
} catch (Exception ex) {
logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));
}
case METHOD:
case SERVICE:
default:
return null;
}

return null;
}

arouter-compiler

arouter-compiler主要负责ARouter定义的注解的解析,关于注解,可以参考文章Java 注解详解在分析之前,需要先了解下ARouter定义了哪些注解,见后面的arouter-annotation小结。

ARouter采用编译时注解,并通过Javapoet库来自动生成代码。

arouter-compiler的结构及说明

1
2
3
4
5
6
7
8
9
10
11
12
com.alibaba.android.arouter.compiler
├── entity
│   └── RouteDoc.java # 生成路由文档时用到
├── processor
│   ├── AutowiredProcessor.java # ARouter参数注解
│   ├── BaseProcessor.java # 注解处理的基类
│   ├── InterceptorProcessor.java # ARouter拦截器注解
│   └── RouteProcessor.java # ARouter路由注解
└── utils
├── Consts.java # 常量定义(里面有ARouter生成文件格式的一些常量定义)
├── Logger.java # 编译时注log的封装
└── TypeUtils.java # Type处理工具类,主要用来进行Type转换

BaseProcessor.java

提供了注解处理需要的一些工具类如FilerLoggerTypesElementsTypeUtils等,init方法中对这些工具类进行了初始化。

RouteProcessor.java

ARouter的核心,核心实现在process()方法中的parseRoutes()方法中,现在对parseRoutes()方法做简单分析。

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
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();
// 获取要处理的类型:Activity、Service、Fragment(app包和support.v4包)
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();

// 获取ARouter定义的接口IRouteGroup和IProviderGroup
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);

/*
采用JavaPoet构建输入参数,即IRouteRoot接口中定义的loadInfo方法的参数,
参数形式为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))
)
);

/*
采用JavaPoet构建输入参数,即IRouteGroup接口中定义的loadInfo方法的参数,
参数形式为:Map<String, RouteMeta>
*/
ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
ClassName.get(RouteMeta.class)
);

/*
采用JavaPoet构建输入参数的名称,分别是:
Map<String, Class<? extends IRouteGroup>> routes、
Map<String, RouteMeta> atlas、
Map<String, RouteMeta> providers
*/
ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build();
ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build(); // Ps. its param type same as groupParamSpec!

/*
采用JavaPoet构建IRouteRoot的loadInfo方法
*/
MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(rootParamSpec);

// 按顺序,先根据RouteMeta返祖,然后生成Java源文件
for (Element element : routeElements) {
TypeMirror tm = element.asType();
Route route = element.getAnnotation(Route.class);
RouteMeta routeMeta;

// 找到添加@Router注解的Activity
if (types.isSubtype(tm, type_Activity)) { // Activity
logger.info(">>> Found activity route: " + tm.toString() + " <<<");

// 获取所有被Autowired注解的Field
Map<String, Integer> paramsType = new HashMap<>(); // 注解参数的类型
Map<String, Autowired> injectConfig = new HashMap<>();
for (Element field : element.getEnclosedElements()) {
if (field.getKind().isField() && field.getAnnotation(Autowired.class) != null && !types.isSubtype(field.asType(), iProvider)) {
// 类型是Field有Autowired注解并且不是IProvider的子类的才处理
Autowired paramConfig = field.getAnnotation(Autowired.class);
// 注入参数名称兼容处理:有的话就去注解的name,没有的话就去改Field的名称
String injectName = StringUtils.isEmpty(paramConfig.name()) ? field.getSimpleName().toString() : paramConfig.name();
// 名称与类型意义对应
paramsType.put(injectName, typeUtils.typeExchange(field));
injectConfig.put(injectName, paramConfig);
}
}
routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY, 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 if (types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {
logger.info(">>> Found fragment route: " + tm.toString() + " <<<");
routeMeta = new RouteMeta(route, element, RouteType.parse(FRAGMENT), null);
} else {
throw new RuntimeException("ARouter::Compiler >>> Found unsupported class type, type = [" + types.toString() + "].");
}
// 利用获取到的routeMeta,生成一个groupMap(提供的Demo中有两个分组,分别是test和yourservicegroupname)
categories(routeMeta);
}

MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(providerParamSpec);

Map<String, List<RouteDoc>> docSource = new HashMap<>();

// 开始生成Java源文件, 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(); // 拿到组名,如test、yourservicegroupname

// Group的loadInfo 方法
MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(groupParamSpec);

List<RouteDoc> routeDocList = new ArrayList<>();

// 根据RouteMeta获取生成文档需要的RouteDocList以及IProvider
Set<RouteMeta> groupData = entry.getValue();
for (RouteMeta routeMeta : groupData) {
RouteDoc routeDoc = extractDocInfo(routeMeta);

ClassName className = ClassName.get((TypeElement) routeMeta.getRawType());

switch (routeMeta.getType()) {
// 处理Providers,生成Provider的loadInfo方法体
case PROVIDER: // Need cache provider's super class
List<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces();
for (TypeMirror tm : interfaces) {
routeDoc.addPrototype(tm.toString());

if (types.isSameType(tm, iProvider)) { // 直接实现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,
routeMeta.getPath(),
routeMeta.getGroup());
} else if (types.isSubtype(tm, iProvider)) {// 实现了IProvider接口的子接口
loadIntoMethodOfProviderBuilder.addStatement(
"providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
tm.toString(), // So stupid, will duplicate only save class name.
routeMetaCn,
routeTypeCn,
className,
routeMeta.getPath(),
routeMeta.getGroup());
}
}
break;
default:
break;
}

// 生成被Autowired注解的参数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();
// 生成Group的loadInfo方法体,atlas为前面定义的groupParamSpec对应的参数名称
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);
}

// 生成Group文件(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);
}

if (MapUtils.isNotEmpty(rootMap)) {
// 先生成group的RootMeta信息,必须在生成ARouter$$Root之前生成,因为后面要用到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()));
}
}

// 输出路由文档
if (generateDoc) {
docWriter.append(JSON.toJSONString(docSource, SerializerFeature.PrettyFormat));
docWriter.flush();
docWriter.close();
}

// 生成ARouter$$Providers$moduleName(moduleName为所在module的名称)
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 + " <<<");

// 生成ARouter$$Root$moduleName(moduleName为所在module的名称)
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);

logger.info(">>> Generated root, name is " + rootFileName + " <<<");
}
}

通过仔细分析上面的源码,可以发现他会生成如下几个文件(按顺序):

  • ARouterGroupName.java(GroupName为@Route注解的第一个 “/“ 后面的内容);
  • arouter-map-of-ModuleName.json(当前模块的json格式文档)
  • ARouterModuleName.java(ModuleName为当前的module名称);
  • ARouterModuleName.java(ModuleName为当前的module名称);

上面的三个java文件生成的同时,对应的会生成相应的loadInto方法,这些方法在aroute-api模块些的LogisticsCenter.init方法中被调用,这样就完成了注册工作。下面看看ARouter生成的Group文件

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
package com.alibaba.android.arouter.routes;

import com.alibaba.android.arouter.demo.BlankFragment;
import com.alibaba.android.arouter.demo.TestWebview;
import com.alibaba.android.arouter.demo.testactivity.Test1Activity;
import com.alibaba.android.arouter.demo.testactivity.Test2Activity;
import com.alibaba.android.arouter.demo.testactivity.Test3Activity;
import com.alibaba.android.arouter.demo.testactivity.Test4Activity;
import com.alibaba.android.arouter.facade.enums.RouteType;
import com.alibaba.android.arouter.facade.model.RouteMeta;
import com.alibaba.android.arouter.facade.template.IRouteGroup;
import java.lang.Override;
import java.lang.String;
import java.util.Map;

/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Group$$test implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/test/activity1", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/activity1", "test", new java.util.HashMap<String, Integer>(){{put("ser", 9); put("ch", 5); put("fl", 6); put("dou", 7); put("boy", 0); put("url", 8); put("pac", 10); put("obj", 11); put("name", 8); put("objList", 11); put("map", 11); put("age", 3); put("height", 3); }}, -1, -2147483648));
atlas.put("/test/activity2", RouteMeta.build(RouteType.ACTIVITY, Test2Activity.class, "/test/activity2", "test", new java.util.HashMap<String, Integer>(){{put("key1", 8); }}, -1, -2147483648));
atlas.put("/test/activity3", RouteMeta.build(RouteType.ACTIVITY, Test3Activity.class, "/test/activity3", "test", new java.util.HashMap<String, Integer>(){{put("name", 8); put("boy", 0); put("age", 3); }}, -1, -2147483648));
atlas.put("/test/activity4", RouteMeta.build(RouteType.ACTIVITY, Test4Activity.class, "/test/activity4", "test", null, -1, -2147483648));
atlas.put("/test/fragment", RouteMeta.build(RouteType.FRAGMENT, BlankFragment.class, "/test/fragment", "test", null, -1, -2147483648));
atlas.put("/test/webview", RouteMeta.build(RouteType.ACTIVITY, TestWebview.class, "/test/webview", "test", null, -1, -2147483648));
}
}

当loadInfo方法别调用后,参数atlas中的值就都存储在了Warehouse中对应的数据结构中了。而Warehouse中的内容会在LogisticsCenter的completion方法调用的时候存储到Postcard(RouteMeta子类)对象中,调用的时机是ARouter的navigation方法。

AutowiredProcessor.java

在介绍Autowired注解之前,先看看使用Autowired注解使用的方法:

  • 初始化ARouter
  • 构建参数并跳转,具体如下:
1
2
3
4
5
6
7
8
9
10
11
12
ARouter.getInstance().build("/test/activity1")
.withString("name", "老王")
.withInt("age", 18)
.withBoolean("boy", true)
.withLong("high", 180)
.withString("url", "https://a.b.c")
.withSerializable("ser", testSerializable)
.withParcelable("pac", testParcelable)
.withObject("obj", testObj)
.withObject("objList", objList)
.withObject("map", map)
.navigation();
  • 在路由为/test/activity1的Activity中,对相应的Filed加上@Autowired注解,如:
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
 @Autowired(desc = "姓名")
String name = "jack";

@Autowired
int age = 10;

@Autowired
int height = 175;

@Autowired(name = "boy", required = true)
boolean girl;

@Autowired
char ch = 'A';

@Autowired
float fl = 12.00f;

@Autowired
double dou = 12.01d;

@Autowired
TestSerializable ser;

@Autowired
TestParcelable pac;

@Autowired
TestObj obj;

@Autowired
List<TestObj> objList;
...
  • 在该Activity(设为Test1Activity)的onCreate中调用ARouter.getInstance().inject()方法。
  • 在编译过后,ARouter会为我们生产一个名为Test1ActivityAutowired的文件,其内容如下:
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
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class Test1Activity$$ARouter$$Autowired implements ISyringe {
private SerializationService serializationService;

@Override
public void inject(Object target) {
serializationService = ARouter.getInstance().navigation(SerializationService.class);
// 将target转换为目标对象(这里是Test1Activity)
Test1Activity substitute = (Test1Activity)target;
substitute.name = substitute.getIntent().getExtras() == null ? substitute.name : substitute.getIntent().getExtras().getString("name", substitute.name);
substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
substitute.height = substitute.getIntent().getIntExtra("height", substitute.height);
substitute.girl = substitute.getIntent().getBooleanExtra("boy", substitute.girl);
substitute.ch = substitute.getIntent().getCharExtra("ch", substitute.ch);
substitute.fl = substitute.getIntent().getFloatExtra("fl", substitute.fl);
substitute.dou = substitute.getIntent().getDoubleExtra("dou", substitute.dou);
substitute.ser = (com.alibaba.android.arouter.demo.testinject.TestSerializable) substitute.getIntent().getSerializableExtra("ser");
substitute.pac = substitute.getIntent().getParcelableExtra("pac");
if (null != serializationService) {
substitute.obj = serializationService.parseObject(substitute.getIntent().getStringExtra("obj"), new com.alibaba.android.arouter.facade.model.TypeWrapper<TestObj>(){}.getType());
} else {
Log.e("ARouter::", "You want automatic inject the field 'obj' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
}
if (null != serializationService) {
substitute.objList = serializationService.parseObject(substitute.getIntent().getStringExtra("objList"), new com.alibaba.android.arouter.facade.model.TypeWrapper<List<TestObj>>(){}.getType());
} else {
Log.e("ARouter::", "You want automatic inject the field 'objList' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
}
if (null != serializationService) {
substitute.map = serializationService.parseObject(substitute.getIntent().getStringExtra("map"), new com.alibaba.android.arouter.facade.model.TypeWrapper<Map<String, List<TestObj>>>(){}.getType());
} else {
Log.e("ARouter::", "You want automatic inject the field 'map' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
}
substitute.url = substitute.getIntent().getExtras() == null ? substitute.url : substitute.getIntent().getExtras().getString("url", substitute.url);
substitute.helloService = ARouter.getInstance().navigation(HelloService.class);
}
}

在这个Inject方法中,完成了被注解的字段的赋值,接下来我们就可以直接使用这些值了。那么这个inject()方法在什么时候被调用呢?看代码:

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
@Route(path = "/arouter/service/autowired")
public class AutowiredServiceImpl implements AutowiredService {
private LruCache<String, ISyringe> classCache;
private List<String> blackList;

@Override
public void init(Context context) {
classCache = new LruCache<>(66);
blackList = new ArrayList<>();
}

@Override
public void autowire(Object instance) {
String className = instance.getClass().getName();
try {
if (!blackList.contains(className)) {
ISyringe autowiredHelper = classCache.get(className);
if (null == autowiredHelper) { // No cache.
autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
}
autowiredHelper.inject(instance);
classCache.put(className, autowiredHelper);
}
} catch (Exception ex) {
blackList.add(className); // This instance need not autowired.
}
}
}

在AutowiredService的实现类AutowiredServiceImpl的autowire方法中,调用了这个方法,这个类做了以下几件事:

  • 实现了参数的绑定(即调用Atowired注解生成的类的的inject方法)
  • 对ISyringe对象(也就是Autowired注解生成的类)做了缓存,采用LRUCache算法实现;
  • 实现了黑名单策略,黑名单中的类不会进行参数的绑定

注意,这个AutowiredServiceImpl也采用了@Route注解,说明我们可以通过ARoute.getInstance().build(“path”).navigation()来获取。开代码确实是通过这种方式获取的。调取最终发生在_ARouter的inject(Object obj)中,代码如下:

1
2
3
4
5
6
static void inject(Object thiz) {
AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
if (null != autowiredService) {
autowiredService.autowire(thiz);
}
}

上面结合源码分析了下Autowired注解参数的绑定过程,现在来具体分析AutowiredProcessor,看看他是如何生成对应的ARouter$$Autowired类的。主要处理逻辑在process方法中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (CollectionUtils.isNotEmpty(set)) {
try {
logger.info(">>> Found autowired field, start... <<<");
// 根据包名对Autowired注解进行分类,并最终放入到parentAndChild这个数据结构中
categories(roundEnvironment.getElementsAnnotatedWith(Autowired.class));
// 利用JavaPoet根据parentAndChild来生成不同类(Activity或Fragment对应的Autowired类)
generateHelper();

} catch (Exception e) {
logger.error(e);
}
return true;
}

return false;
}

需要注意一点的是,对象参数的传递用到了SerializationService的parseObject来实现的,现将要传递的参数转换成序列换从json字符串,再在使用的时候反序列化成相应的对象来实现的。

generateHelper()是具体生成代码的实现,主要使用的是JavaPoet,这里不再赘述。

InterceptorProcessor.java

ARouter的一大特点就是支持自定义多个拦截器,并支持自定义顺序,那么这是怎么实现的呢。
_ARouter的navigation关于拦截器的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if (!postcard.isGreenChannel()) {   // 拦截操作需要在异步线程中操作,不然会ANR
// 利用interceptorService(InterceptorService的实现类)来进行拦截此昂管操作),传递一个InterceptorCallback回调
interceptorService.doInterceptions(postcard, new InterceptorCallback() {

@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());
}
});
}

看看InterceptorService实现类:

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
public class InterceptorServiceImpl implements InterceptorService {
// 是否初始化
private static boolean interceptorHasInit;
// 初始化锁
private static final Object interceptorInitLock = new Object();

@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来实现拦截器的优先级,CountDownLatch是一个同步工具类,
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
// 开始执行Interceptor的process方法
_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);
}
}

/**
* 拦截器执行
*
* @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) {
// 计数器-1
counter.countDown();
_excute(index + 1, counter, postcard);
}

@Override
public void onInterrupt(Throwable exception) {
postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage()); // save the exception message for backup.
// 计数器-1
counter.cancel();
}
});
}
}

// InterceptorServiceImpl的初始化方法都在LogisticsCenter的completion方法中调用
@Override
public void init(final Context context) {
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
// 从注册的Interceptor中逐个取出,调用其初始化方法
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {
Class<? extends IInterceptor> interceptorClass = entry.getValue();
try {
IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
// 调用自定义拦截器的init方法
iInterceptor.init(context);
Warehouse.interceptors.add(iInterceptor);
} catch (Exception ex) {
throw new HandlerException(TAG + "ARouter init interceptor error! name = [" + interceptorClass.getName() + "], reason = [" + ex.getMessage() + "]");
}
}

interceptorHasInit = true;

logger.info(TAG, "ARouter interceptors init over.");
// 通知
synchronized (interceptorInitLock) {
interceptorInitLock.notifyAll();
}
}
}
});
}

// 初始化状态检查,ARouter的init方法调用后,会调用afterInit方法,该方法中会初始化interceptorService。
private static void checkInterceptorsInitStatus() {
synchronized (interceptorInitLock) {
while (!interceptorHasInit) {
try {
interceptorInitLock.wait(10 * 1000);
} catch (InterruptedException e) {
throw new HandlerException(TAG + "Interceptor init cost too much time error! reason = [" + e.getMessage() + "]");
}
}
}
}
}

对上面代码做几点说明:

  1. 拦截器的同步执行是通过CountDownLatch来实现的;
  2. 拦截器的顺序(优先级)有init方法中来实现,init方法中会迭代Warehouse.interceptorsIndex(这是一个UniqueTreeMap结构,它是有序的)

arouter-annotation

arouter-annotation的结构

1
2
3
4
5
6
7
8
9
10
11
12
com/alibaba/android/arouter/facade
├── annotation
│   ├── Autowired.java // 参数注解
│   ├── Interceptor.java // 拦截器注解
│   ├── Param.java // 参数注解,已废弃
│   └── Route.java // 路由注解
├── enums
│   ├── RouteType.java // 路由的类型
│   └── TypeKind.java //
└── model
├── RouteMeta.java // 路由元数据信息(核心,后面用到的Postcard使用的是这个)
└── TypeWrapper.java // 对象包装类

总结

本文篇幅较长,从使用入手,借助ARouter Demo生成的文件从源码入手,分析了ARouter的具体实现,主要流程其实如下:

  • 使用注解 编译,生成相应的类;
  • 调用初始化方法,初始化方法最后会LogisticsCenter.init方法,这个方法中会调用编译生成类的loadInfo方法,将路由信息、拦截器信息、Group信息加载到Warehouse中(内存中)
  • 上面的loadInfo完成了路由path的映射,同时完成了RouteMeta的创建;
  • 在调用ARouter.getInstance().navigation()方法时,LogisticsCenter.completion方法会将RouteMeta转换为Postcard,完善信息,然后最终交由_navigation进行跳转的处理
  • 对于@Autowired注解,注解处理器处理后,在调用ARouter.getInstance().inject()后,会完成参数的绑定。

ARouter Activity跳转本质上还是调用startActivity方法的。传递的信息都在Postcard中。