0%

ARouter 源码简析

0. 前言

ARouter 是 Android 平台中对页面、服务提供路由功能的中间件,由阿里开发并在 Github 开源,主要应用场景如下:

  1. 从外部URL映射到内部页面,以及参数传递与解析
  2. 跨模块页面跳转,模块间解耦
  3. 拦截跳转过程,处理登陆、埋点等逻辑
  4. 跨模块API调用,通过控制反转来做组件解耦

本文将对 ARouter 的源码进行分析,学习该路由库的设计思想。

1. 从用法谈起

想要分析 ARouter,我们先回顾它的用法。ARouter 对外 API 简单易懂,用起来很方便,第一步便是初始化,要尽可能放在最前,即 Application 中:

1
2
3
ARouter.openDebug(); // 开发模式下打开Debug
ARouter.init(getApplication()); // 全局初始化
// ARouter.getInstance().destroy(); 对应销毁

接下来,通过 @Route 注解标记我们需要路由的界面或服务提供者,并进行跳转:

1
2
3
4
5
6
7
8
// 标记,path为自定义路径,必须两级斜杠,第一级默认为分组名
@Route(path = "/test/activity2")
public class Test2Activity extends AppCompatActivity {
...
}

// 跳转
ARouter.getInstance().build("/test/activity2").navigation();

上面便是最基础的用法,我们还可以使用 @Autowired 注解为它注入 Intent 参数:

1
2
3
4
5
6
// 目标组件成员变量添加注解
@Autowired
String key1;

// 在onCreate()添加注入
ARouter.getInstance().inject(this);

除了这些,还有很多有趣、实用的功能,本文偏重于源码分析,这里就不细讲每一种用法,对用法不熟悉的读者还请自行查阅了解。

接下来,我们围绕用法,来看看源码中是如何实现这些功能的。

2. 编译期做的事

编译期做的事情和许多框架一样,用到了 APT(注解处理工具)技术,主要是对三种注解:@Route@Autowired@Interceptor 进行解析,生成相应的处理代码。

WX20180323-192017@2x.png

图为编译期预处理模块的工程结构,processor 包中为三种注解的处理和代码生成逻辑,其中代码生成也用到的事 JavaPoet 来实现,这里的逻辑没有必要分析,让我们直接来看生成的代码:

(1)RouteRoot

WX20180323-194446@2x.png

一个 APP 中会有多个组,每个组内会有多个带有路径 path 的组件。(组名默认为 path 属性的一级划分,如 path『/test/activity1』的组名为『test』)

这里是对组的管理,loadInto() 方法可以将组信息加载到参数 routes 中。可以看到 Demo 中包含两个组,『service』和『test』,可以猜测,其关联的两个类便是一个组对组内所有路径组件的管理:

WX20180323-195305@2x.png

其中,RouteMeta 是对路由信息存储的容器类:

1
2
3
4
5
6
7
8
9
10
11
public class RouteMeta {
private RouteType type; // 目标组件类型
private Element rawType; // 原始类型,工程中暂未出现使用
private Class<?> destination; // 目标类
private String path; // 注解指定的字符串path
private String group; // 分组
private int priority = -1; // 优先级,针对拦截器
private int extra; // 额外数据
private Map<String, Integer> paramsType; // 参数key和类型
...
}

(2)ProviderGroup

WX20180323-194600@2x.png

ARouter 中有一个概念就是 Provider(服务提供者),Provider 就是用来提供服务的,比如 ARouter 的一些内部功能类或是拦截器,都属于 Provider。

Provider 和 Activity 组件一样都可以被路由,只是 Provider 返回的只是一个初始化后的实例,因为它不能像 Activity 一样有跳转事件。

这里的 ProviderGroup 很明显便是对这些提供者的加载管理,它关联了全类名和 RouteMeta 路由信息。

(3)InterceptorGroup

WX20180323-194659@2x.png

拦截器主要用来拦截路由跳转过程,当中可以进行如登录判断的操作,便于逻辑层面的简化。

此处 InterceptorGroup 便是对拦截器的加载管理,它关联的是拦截器优先级和拦截器实现类。

(4)Autowired

WX20180323-200553@2x.png

不要忘记还会生成注入类,inject() 方法将 target(即目标组件)中的成员变量依次进行赋值注入。

编译期做的事情主要便是生成上述的几个类,接下来开始正式顺着运行流程对 ARouter 进行分析。

3. 初始化起点

没有多余的配置,ARouter 的初始化只需一行代码即可,来看看做了什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// class ARouter

public static void init(Application application) {
// 是否已经初始化,destroy()方法置为false
if (!hasInit) {
// 日志
logger = _ARouter.logger;
_ARouter.logger.info(Consts.TAG, "ARouter init start.");
// 真正的初始化
hasInit = _ARouter.init(application);

if (hasInit) {
// 初始化后续操作
_ARouter.afterInit();
}
_ARouter.logger.info(Consts.TAG, "ARouter init over.");
}
}

可见,真正的操作都在 _ARouter 中,并且 _ARouter 中都是静态方法,进入到 _ARouter:

1
2
3
4
5
6
7
8
9
10
// class _ARouter

protected static synchronized boolean init(Application application) {
mContext = application;
// 路由图的初始化和加载
LogisticsCenter.init(mContext, executor);
logger.info(Consts.TAG, "ARouter init success!");
hasInit = true;
return true;
}

这里调用的是 LogisticsCenter 中的方法进行初始化,LogisticsCenter 中才是 ARouter 的真正核心逻辑处理:

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
// class LogisticsCenter

public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
mContext = context;
executor = tpe;
try {
long startInit = System.currentTimeMillis();
// 加载路由信息到Warehouse类中存储
// 先尝试用 Gradle 编译插件加载
loadRouterMap();
if (registerByPlugin) {
// 采用插件加载
logger.info(TAG, "Load router map by arouter-auto-register plugin.");
} else {
// 插件加载不成功时,用常规方式加载
Set<String> routerMap;

// 在调试模式下,或者升级应用版本后,需要重新构建路由图
// 这就是为什么使用时要先调用 ARouter.openDebug();
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
// 取得com.alibaba.android.arouter.routes包下面生成的类,类名集合
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
if (!routerMap.isEmpty()) {
// 缓存到SharedPreferences中去
context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
}
// 更新版本号
PackageUtils.updateVersion(context);
} else {
logger.info(TAG, "Load router map from cache.");
// 从缓存中读取路由图
routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
}

...

for (String className : routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
// com.alibaba.android.arouter.routes.ARouter$$Root
// 加载组信息到Warehouse.groupsIndex,每个组管理该组内path和RouteMeta关联
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
// com.alibaba.android.arouter.routes.ARouter$$Interceptors
// 加载拦截器到Warehouse.interceptorsIndex
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
// com.alibaba.android.arouter.routes.ARouter$$Providers
// 加载Provider
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
}

...
} catch (Exception e) {
...
}
}

PS:这里讲一个 Android Studio 中去除代码缩进的技巧,就是选中代码块然后 Shift + Tab 键同时按,便可去除缩进(直接按 Tab 键是增加缩进),这个技巧在写博客复制无缩进的代码是挺有用的。

LogisticsCenter 中初始化方法做的事情看起来很复杂,其实很容易,就是将我们在编译期生成的 InterceptorGroupProviderGroupRouteRoot 实例化,然后调用它们的 loadInto() 方法,将它们管理的拦截器、提供者、路由组件信息加载到 Warehouse 类中进行缓存,看看 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
class Warehouse {
// Cache route and metas
// group和groupMeta关联
static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
// path和RouteMeta关联
static Map<String, RouteMeta> routes = new HashMap<>();

// Cache provider
// 对于Provider,目标Class和IProvider实现关联
static Map<Class, IProvider> providers = new HashMap<>();
// 全类名和RouteMeta关联
static Map<String, RouteMeta> providersIndex = new HashMap<>();

// 拦截器,优先级和实现类关联,优先级标识具有唯一性
static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex
= new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
// 存放所有拦截器实例
static List<IInterceptor> interceptors = new ArrayList<>();

static void clear() {
routes.clear();
groupsIndex.clear();
...
}
}

Warehouse 的用途就是缓存这些路由信息,供全局查询。这里分析了 _ARouter 中的初始化,回过头来,还得看看 _ARouter.afterInit() 的补充流程:

1
2
3
4
static void afterInit() {
// 取得InterceptorServiceImpl实例
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}

初始化后,ARouter 就可以用了,这里拦截器便使用自己的『Provider』功能来完成自己的内部 InterceptorServiceImpl 的实例化,稍后的『跳转』分析中可以看到 Provider 实例化的工作流程。

4. 如何实现的跳转

跳转的用法分两步走,build 和 navigation,如下所示:

1
2
3
ARouter.getInstance()
.build("/test/activity2") // 构造Postcard
.navigation(); // 跳转

同上文,build() 方法也是在 _ARouter 类中实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// class _ARouter

protected Postcard build(String path) {
if (TextUtils.isEmpty(path)) {
throw new HandlerException(Consts.TAG + "Parameter is invalid!");
} else {
// 路径替换
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
// 创建Postcard对象,填充path和group
return build(path, extractGroup(path));
}
}

首先实例化 PathReplaceService 的实现类,PathReplaceService 用于将指定的路径进行拦截后做一个全局修改,类似于 URL 中对相对 URL 进行拦截后修改为绝对 URL,看下 PathReplaceService 的定义:

1
2
3
4
public interface PathReplaceService extends IProvider {
String forString(String path);
Uri forUri(Uri uri);
}

当然,这里不需要进行替换,没有实现类,所以直接跳到 return 语句,首先是取得组名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// class _ARouter

private String extractGroup(String path) {
...

try {
// 取出默认组名
// "/test/activity1" --> "test"
// "/activity1" --> null
String defaultGroup = path.substring(1, path.indexOf("/", 1));
if (TextUtils.isEmpty(defaultGroup)) {
throw new HandlerException(Consts.TAG + "Extract the default group failed! There's nothing between 2 '/'!");
} else {
return defaultGroup;
}
} catch (Exception e) {
return null;
}
}

不指定组名情况下,默认选择路径的一级斜杠,之后进入 build() 重载方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
protected Postcard build(String path, String group) {
if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
throw new HandlerException(Consts.TAG + "Parameter is invalid!");
} else {
// 路径替换
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
// new一个Postcard
return new Postcard(path, group);
}
}

这里和其重载方法的路径替换操作有些重复,也重复进行了一次路径替换,然后返回 Postcard 的实例,来看看 Postcard 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 存放路由目的地和参数信息,继承自RouteMeta
public final class Postcard extends RouteMeta {
private Uri uri; // 目的Uri
private Object tag; // 标记异常信息,拦截器中抛出
private Bundle mBundle; // 携带的参数
private int flags = -1; // Activity的启动Flag
private int timeout = 300; // 跳转超时,主要拦截器耗时
private IProvider provider; // 如果是Provider,存放其实例,直接返回
private boolean greenChannel; // 绿色通道,不经过拦截器
private SerializationService serializationService; // Bundle携带Object的序列化服务
private Bundle optionsCompat; // ActivityOptionsCompat切屏动画
private int enterAnim = -1; // 进入动画res id
private int exitAnim = -1; // 退出动画res id

...

}

可见 Postcard 继承自 RouteMeta(前文已提及类定义),其中存放了路由操作需要的所有信息,这里 build() 方法中 new 实例则是将 path 和 group 属性赋值。

那么还有这么多的其它属性从哪里获得呢,不要忘记之前的初始化操作,初始化操作中调用了编译期生成类的 loadInto() 方法,其加载路由信息到 Warehouse,而这些信息正是 RouteMeta 信息,所以下一步要做的便是从 Warehouse 中取出加载好的 RouteMeta 信息,然后填充到我们的 Postcard 中来,继续分析,验证我们的猜想是否正确。

接下来,第二步便是 navigation 操作,方法定义在 Postcard 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
// class Postcard

public Object navigation(Context context, NavigationCallback callback) {
// 调用ARouter中的方法
return ARouter.getInstance().navigation(context, this, -1, callback);
}

// class ARouter

public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {
// 调用_ARouter中的方法
return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);
}

最终还是传递到 _ARouter 中的方法:

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
// class _ARouter

protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
try {
// 根据RouteMeta等填充postcard
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
...
}

if (null != callback) {
callback.onFound(postcard);
}

if (!postcard.isGreenChannel()) {
// 非绿色通道便要执行拦截器
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);
}
}
});
} else {
return _navigation(context, postcard, requestCode, callback);
}

return null;
}

这里的 navigation() 方法中,首先,如我们猜想,调用了 LogisticsCenter.completion() 方法填充 Postcard 的属性,然后调用拦截器,最后真正的跳转在 _navigation() 方法中。

先来看如何填充 Postcard 的属性,来到 LogisticsCenter.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
90
// class LogisticsCenter

public synchronized static void completion(Postcard postcard) {
...
// 从Warehouse.routes取出缓存的RouteMeta信息
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
// 判断RouteMeta是否存在
if (null == routeMeta) {
// Warehouse.routes中不存在或者未加载
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());
// 取出组名对应的组管理类,即生成的RouteGroup
if (null == groupMeta) {
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
try {
...
// 创建RouteGroup实例
// loadInto()加载RouteMeta到Warehouse.routes
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
iGroupInstance.loadInto(Warehouse.routes);
Warehouse.groupsIndex.remove(postcard.getGroup());
...
}
} catch (Exception e) {
throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
}
// 加载完成,重新执行一遍该函数
completion(postcard);
}
} else {
// 填充额外信息
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.
// 从Uri取出参数,填充到Postcard.mBundle
Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
Map<String, Integer> paramsType = routeMeta.getParamsType();

if (MapUtils.isNotEmpty(paramsType)) {
// 依次添加
for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
setValue(postcard,
params.getValue(),
params.getKey(),
resultMap.get(params.getKey()));
}

// 标识需要自动注入的参数,空数组,可能暂未实现
postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
}

// 保存原始带参数的URI
postcard.withString(ARouter.RAW_URI, rawUri.toString());
}
// 分类型做处理
switch (routeMeta.getType()) {
case PROVIDER:
// 如果是Provider,需要取得实例并赋值
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
IProvider instance = Warehouse.providers.get(providerMeta);
if (null == instance) {
// 如果没有缓存有实例,则实例化并缓存
IProvider provider;
try {
provider = providerMeta.getConstructor().newInstance();
// 调用Provider的初始化
provider.init(mContext);
Warehouse.providers.put(providerMeta, provider);
instance = provider;
} catch (Exception e) {
throw new HandlerException("Init provider failed! " + e.getMessage());
}
}
// 然后填充到postcard
postcard.setProvider(instance);
// Provider标记为绿色通道,不经过拦截器
postcard.greenChannel();
break;
case FRAGMENT:
// Fragment也标记绿色通道,不经过拦截器
postcard.greenChannel();
default:
break;
}
}
}

至此,Postcard 中需要的属性都填充完毕,其中还包含是否为绿色通道的属性,绿色通道将不经过拦截器。接下来看拦截操作的执行:

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
@Route(path = "/arouter/service/interceptor")
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() {
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
// 递归执行完所有拦截器,注意是所有拦截器
_excute(0, interceptorCounter, postcard);
// 设置拦截器超时等待
interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
// 可能超时,可能正常终止计数归0,可能异常终止计数归0
if (interceptorCounter.getCount() > 0) {
callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
} else if (null != postcard.getTag()) {
// 某个拦截器抛出错误
callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
} else {
// 正常终止
callback.onContinue(postcard);
}
} catch (Exception e) {
callback.onInterrupt(e);
}
}
});
} else {
callback.onContinue(postcard);
}
}

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) {
// 释放一个CountDownLatch计数
counter.countDown();
// 依次执行下一个拦截器
_excute(index + 1, counter, postcard);
}

@Override
public void onInterrupt(Throwable exception) {
// 将异常信息设置到Postcard的tag属性
postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage());
// 释放所有CountDownLatch计数
counter.cancel();
}
});
}
}

@Override
public void init(final Context context) {
// 异步初始化
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {
// 实例化所有拦截器,加入到Warehouse.interceptors
Class<? extends IInterceptor> interceptorClass = entry.getValue();
try {
IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
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();
}
}
}
});
}

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() + "]");
}
}
}
}
}

InterceptorServiceImpl 会将所有标记 @Interceptor 的拦截器进行实例化,并在每一次跳转(非绿色通道)时,按优先级顺序执行所有的拦截器。

在所有拦截器都放行通过后,接下来便进入真正的跳转逻辑:

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
// class _ARouter

private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
// 确保context有效
final Context currentContext = null == context ? mContext : context;

// 分类型处理
switch (postcard.getType()) {
case ACTIVITY:
// 构造Intent
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());

// 设置Activity Flags
int flags = postcard.getFlags();
if (-1 != flags) {
intent.setFlags(flags);
} else if (!(currentContext instanceof Activity)) { // Non activity, need less one flag.
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}

// 主线程中执行跳转
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// start activity
if (requestCode > 0) {
// startActivityForResult()
// requestCode和context是同时传递的参数
ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
} else {
ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());
}

// 配置动画,Activity Context才有效
if ((-1 != postcard.getEnterAnim() && -1 != postcard.getExitAnim()) && currentContext instanceof Activity) { // Old version.
((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());
}

// 回调跳转
if (null != callback) {
callback.onArrival(postcard);
}
}
});

break;
case PROVIDER:
// 对于Provider,返回IProvider实现实例即可
return postcard.getProvider();
case BOARDCAST:
case CONTENT_PROVIDER:
case FRAGMENT:
// 对于广播、内容提供者、Fragment,返回其实例即可,需要提供默认构造器
Class fragmentMeta = postcard.getDestination();
try {
Object instance = fragmentMeta.getConstructor().newInstance();
// Fragment需要提供参数
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;
}

对于 Activity 这类可跳转组件,调用 startActivity() 进行跳转,对于 Provider、Fragment 这类非跳转组件,返回其实例即可。

以上便是 ARouter 的主要功能,接下来再分析一下参数注入的实现。

5. 参数的注入

参数注入需要我们在组件的 onCreate() 方法中调用 inject() 方法,来看看:

1
2
3
4
5
// class ARouter

public void inject(Object thiz) {
_ARouter.inject(thiz);
}

再来看 _ARouter 中真正的实现:

1
2
3
4
5
6
7
8
9
10
// class _ARouter

static void inject(Object thiz) {
// 构造AutowiredServiceImpl实例
AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
if (null != autowiredService) {
// 调用autowire()方法,参数为组件类
autowiredService.autowire(thiz);
}
}

这里也是用自己的『Provider』功能完成自己的需求,取得的实例是 AutowiredServiceImpl,调用其 autowire() 方法:

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
@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) {
// 没有缓存
// 反射实例化:类名+$$ARouter$$Autowired类
// 之所以类名开头是为了和原类处于同一包中
autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
}
// 调用inject()
autowiredHelper.inject(instance);
// 放入缓存
classCache.put(className, autowiredHelper);
}
} catch (Exception ex) {
// 反射失败,说明没有找到生成的类,也就是不需要注入,拉入黑名单
blackList.add(className);
}
}
}

AutowiredServiceImpl 中主要是将编译器生成名为『原类名+$$ARouter$$Autowired』的类实例化,然后调用其 inject() 方法,来看一看生成的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 编译期生成的类

/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class Test2Activity$$ARouter$$Autowired implements ISyringe {
private SerializationService serializationService;

@Override
public void inject(Object target) {
// 序列化服务,用于Object类型
serializationService = ARouter.getInstance().navigation(SerializationService.class);
// 强转为组件类的类型
Test2Activity substitute = (Test2Activity)target;
// 包访问权限,可以直接赋值
substitute.key1 = substitute.getIntent().getStringExtra("key1");
}
}

很容易理解,startActivity 时将参数放进了 Intent,这里从 Intent 取出参数,再赋值给包访问权限的组件属性,至此,ARouter 的参数注入也就分析完毕了。

6. 结语

本文围绕 ARouter 的基本用法对其源码进行了简要分析,梳理了组件路由的整个流程。简单来说,ARouter 就是通过 APT 技术在编译期事先生成路由图信息,之后运行期根据路由图信息构造跳转参数和行为,通过拦截器后,在目标组件生命周期开始时注入参数,如此实现简洁的路由功能。