0%

Android-Arouter源码解析

概述

Arouter: 阿里开源的一个用于帮助 Android App 进行组件化改造的框架,支持模块间的路由、通信、解耦。具体使用参考官方文档 Arouter。典型应用:

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

初始化

ARouter 在使用前需要通过 ARouter.init(Application) 初始化:

1
2
3
4
5
6
7
8
9
public static void init(Application application) {
if (!hasInit) {
hasInit = _ARouter.init(application);

if (hasInit) {
_ARouter.afterInit();
}
}
}

这里都是调用的 _ARouter 类中的方法,说明 _ARouter 才是核心类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected static synchronized boolean init(Application application) {
mContext = application;
LogisticsCenter.init(mContext, executor);
hasInit = true;
mHandler = new Handler(Looper.getMainLooper());
return true;
}

// LogisticsCenter init, load all metas in memory. Demand initialization
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
mContext = context;
executor = tpe;
// 加载 routerMap 路由表
}

加载 routerMap 有两种方式:通过 arouter-auto-register gradle 插件注册和代码注册。

至于 afterInit 方法则是在初始化成功后初始化拦截器:

1
2
3
4
static void afterInit() {
// Trigger interceptor init, use byName.
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}

arouter-auto-register插件注册

1
2
3
4
5
6
7
8
private static void loadRouterMap() {
registerByPlugin = false;
// 会通过 gradle 插件: arouter-auto-register 来自动生成如下类似代码:
// registerRouteRoot(new ARouter..Root..modulejava());
// registerRouteRoot(new ARouter..Root..modulekotlin());
// registerInterceptor(...)
// ...
}

举例看一下 registerXXX 方法的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
private static void registerRouteRoot(IRouteRoot routeRoot) {
markRegisteredByPlugin();
if (routeRoot != null) {
routeRoot.loadInto(Warehouse.groupsIndex);
}
}

private static void registerInterceptor(IInterceptorGroup interceptorGroup) {
markRegisteredByPlugin();
if (interceptorGroup != null) {
interceptorGroup.loadInto(Warehouse.interceptorsIndex);
}
}

跟代码注册类似,都是将生成的类存入 Warehouse 中,只不过将这一步骤通过 gradle 插件自动化了而已。

代码注册

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
Set<String> routerMap;
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
// debug 模式或是新的版本则会重新加载路由表
// These class was generated by arouter-compiler.
// 通过指定包名,扫描包下面包含的所有的ClassName
routerMap = ClassUtils.getFileNameByPackageName(mContext, "com.alibaba.android.arouter.routes");
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 {
// 从缓存中获取路由表
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("com.alibaba.android.arouter.routes.ARouter$$Root")) {
// This one of root elements, load root.
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith("com.alibaba.android.arouter.routes.ARouter$$Interceptors")) {
// Load interceptorMeta
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith("com.alibaba.android.arouter.routes.ARouter$$Providers")) {
// Load providerIndex
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}

Warehouse 是仓库的意思,它存放了 ARouter 自动生成的类(RouteRoot, InterceptorGroup, ProviderGroup)的信息。初始化过程主要完成了对自动生成的路由相关类 RouteRoot、Interceptor、ProviderGroup 的加载,对它们通过反射构造后将信息加载进了 Warehouse 类中。

路由跳转

Postcard创建

先从 ARouter.build 方法开始:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ARouter
public Postcard build(String path) {
return _ARouter.getInstance().build(path);
}

// _ARouter
protected Postcard build(String path) {
// path 不为空
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
return build(path, extractGroup(path), true);
}

如果 pService 为空,即用户没有实现 PathReplaceService 接口,则通过 build(path, group, afterReplace) 方法获取 Postcard 对象,而 extractGroup 获取 group 的逻辑其实就是取 path 中第一个 / 中的内容作为默认 group:

1
2
3
4
5
6
7
8
9
10
11
protected Postcard build(String path, String group, Boolean afterReplace) {
// path 和 group 不为空
if (!afterReplace) { // 通过 afterReplace 判断是否需要 PathReplaceService 来对 path 进行预处理。
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
}
// 创建一个新的 Postcard 对象
return new Postcard(path, group);
}

在创建了 Postcard 对象后通过 withXXX 方法添加参数,其实就是将参数放入了 Postcard 中的 Bundle 属性中。

执行跳转

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
// Postcard
public Object navigation() {
return navigation(null);
}

public Object navigation(Context context) {
return navigation(context, null);
}

public Object navigation(Context context, NavigationCallback callback) {
return ARouter.getInstance().navigation(context, this, -1, callback);
}

// ARouter
public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {
return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);
}

// _ARouter
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
// 用户没有自定义 PretreatmentService 或自定义 onPretreatment 返回 false 则终止 navigation 跳转
return null;
}

postcard.setContext(null == context ? mContext : context);
// 补全 postcard,它会将我们配置的一些属性等补全
LogisticsCenter.completion(postcard);

if (null != callback) {
callback.onFound(postcard);
}
// 如果设置了 greenChannel 则会跳过所有拦截器的执行
if (!postcard.isGreenChannel()) { // It must be run in async thread, maybe interceptor cost too mush time made ANR.
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
@Override
public void onContinue(Postcard postcard) {
_navigation(postcard, requestCode, callback);
}

@Override
public void onInterrupt(Throwable exception) {
if (null != callback) {
callback.onInterrupt(postcard);
}
}
});
} else {
return _navigation(postcard, requestCode, callback);
}
return null;
}

在补全了 Postcard 以及处理了拦截器的逻辑后,即执行真正的跳转逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = postcard.getContext();

switch (postcard.getType()) {
case ACTIVITY:
// 构建 Intent 并执行 startActivity 方法
break;
case PROVIDER:
return postcard.getProvider();
case BOARDCAST:
case CONTENT_PROVIDER:
case FRAGMENT:
Class<?> fragmentMeta = postcard.getDestination();
// 通过反射 fragmentMeta 获取实例并设置参数,然后将其返回
case METHOD:
case SERVICE:
default:
return null;
}

return null;
}

获取Service

ARouter 除了可以通过 ARouter.getInstance().build().navigation() 这样的方式实现页面跳转之外,还可以通过 ARouter.getInstance().navigation(XXService.class) 这样的方式实现跨越组件的服务获取:

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
public <T> T navigation(Class<? extends T> service) {
return _ARouter.getInstance().navigation(service);
}

protected <T> T navigation(Class<? extends T> service) {
try {
Postcard postcard = LogisticsCenter.buildProvider(service.getName());
if (null == postcard) {
return null;
}
postcard.setContext(mContext);
LogisticsCenter.completion(postcard);
return (T) postcard.getProvider();
} catch (NoRouteFoundException ex) {
return null;
}
}

public static Postcard buildProvider(String serviceName) {
RouteMeta meta = Warehouse.providersIndex.get(serviceName);

if (null == meta) {
return null;
} else {
return new Postcard(meta.getPath(), meta.getGroup());
}
}

上面通过 buildProvider 方法创建对应 service 的 Postcard 对象,然后补全 Postcard 信息。其中 buildProvider 方法就是通过 Warehouse 中已经初始化的 providersIndex 根据 serviceName 获取对应的 RouteMeta,之后根据 RouteMeta 的 path 和 group 创建对应的 Postcard 对象。

拦截器机制

拦截器执行的入口在 InterceptorService.doInterceptions 方法中:

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
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
// 在线程池中执行
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
try {
_execute(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((Throwable) postcard.getTag());
} else {
callback.onContinue(postcard);
}
} catch (Exception e) {
callback.onInterrupt(e);
}
}
}
} else {
callback.onContinue(postcard);
}
}

上面通过创建一个拦截器大小的 CountDownLatch 对象,用其来保证所有拦截器执行完毕后才接着执行其它逻辑。看看 _execute 方法的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private static void _execute(final int index, final CancelableCountDownLatch counter, final Postcard postcard) {
if (index < Warehouse.interceptors.size()) {
// 顺序获取对应 index 的拦截器
IInterceptor iInterceptor = Warehouse.interceptors.get(index);
iInterceptor.process(postcard, new InterceptorCallback() {
@Override
public void onContinue(Postcard postcard) {
counter.countDown(); // CountDownLatch 减 1
_execute(index + 1, counter, postcard); // 执行下一个拦截器
}

@Override
public void onInterrupt(Throwable exception) {
postcard.setTag(null == exception ? new HandlerException("No message.") : exception);
counter.cancel();
}
});
}
}

注解处理

ARouter 通过注解处理器在编译期间,使用 JavaPoet 生成了一系列 Java 文件,如 RouteRoot、ProviderGroup、Provider、Interceptor 的子类等。看一下 Warehouse 类中的相关数据结构。

ARouter 会根据 @Route 注解中的 group 生成对应名称的类。所以如果在不同的子模块下声明了相同的 group 路由,那么会生成同一个名字的两个类,添加到 groupsIndex 中的只会是其中一个,那么另一个类中 @Route 注册的组件会找不到。

route and metas

1
2
3
4
// group -- 每个group生成的类,形如ARouter$$Group$$service
static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
// path -- Route信息
static Map<String, RouteMeta> routes = new HashMap<>();

生成的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ARouter$$Group$$service implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/service/json", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/service/json", "service", null, -1, -2147483648));
}
}

public class ARouter$$Group$$test implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/app/myprovider", RouteMeta.build(RouteType.PROVIDER, MyProvider.class, "/app/myprovider", "test", null, -1, -2147483648));
}
}

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

provider

1
2
3
4
5
// Cache provider
// provider类 -- provider实例
static Map<Class, IProvider> providers = new HashMap<>();
// provider类名 -- Route信息
static Map<String, RouteMeta> providersIndex = new HashMap<>();

生成的类:

1
2
3
4
5
6
7
public class ARouter$$Providers$$app implements IProviderGroup {
@Override
public void loadInto(Map<String, RouteMeta> providers) {
providers.put("com.hearing.arouter.MyProvider", RouteMeta.build(RouteType.PROVIDER, MyProvider.class, "/app/myprovider", "test", null, -1, -2147483648));
providers.put("com.alibaba.android.arouter.facade.service.SerializationService", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/service/json", "service", null, -1, -2147483648));
}
}

interceptor

1
2
3
4
// index -- 拦截器实现类
static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
// 拦截器实例列表
static List<IInterceptor> interceptors = new ArrayList<>();

生成的类:

1
2
3
4
5
6
public class ARouter$$Interceptors$$app implements IInterceptorGroup {
@Override
public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
interceptors.put(1, LoginInterceptor.class);
}
}

Autowired

1
2
3
4
5
6
7
8
9
10
11
12
public class LoginActivity$$ARouter$$Autowired implements ISyringe {
private SerializationService serializationService;

@Override
public void inject(Object target) {
serializationService = ARouter.getInstance().navigation(SerializationService.class);
LoginActivity substitute = (LoginActivity)target;
substitute.userName = substitute.getIntent().getExtras() == null ? substitute.userName : substitute.getIntent().getExtras().getString("userName", substitute.userName);
substitute.userPassword = substitute.getIntent().getExtras() == null ? substitute.userPassword : substitute.getIntent().getExtras().getString("userPassword", substitute.userPassword);
substitute.person = substitute.getIntent().getExtras() == null ? substitute.person : substitute.getIntent().getExtras().getString("person", substitute.person);
}
}

总结

ARouter 的核心流程可以分成三个步骤:

  1. 编译期注解处理:通过注解处理器配合 JavaPoet 实现了在编译期间生成 IRouteRoot, IProviderGroup, IProvider, IInterceptor 等的子类,在这些类中会装载注解相关的信息;
  2. 初始化:通过 ARouter.init 方法,查找 com.alibaba.android.arouter.routes 包下的所有类,这些都是第一步中注解处理器生成的类。然后将这些类信息存入 Warehouse 中的对应容器里。
  3. 路由查找:通过 navigation 方法,从 Warehouse 中查找对应信息并执行相应逻辑。