这篇文章主要分析ARouter中路由与服务相关的源码(不涉及依赖注入)。
路由框架要解决哪些问题?
在开始源码分析之前,先考虑一下这个问题。
在这一节,会抛出几个问题,而下面的源码分析,就会围绕这一节的问题而展开。
1、路由信息如何搜集?
2、如何完成跳转,如何传参?
3、跳转过程中需要插入一些公用逻辑怎么办?
4、跳转过程中出现异常或者跳转失败怎么办?
框架整体设计
在开始具体的代码流程分析之前,可以先大致了解下框架的整体设计。简单整理下主要的类与模块,可以得到下面的结构图:

简单介绍下每个类或模块的大概职责。
ARouter
外部调用的最主要功能接口,提供路由跳转的入口。
IProvider
服务提供者的抽象。
annotation
因为ARouter的基本实现是基于APT的,所以需要通过annotation暴露路由注册功能。
_Arouter
路由跳转的具体实现。
LogisticsCenter
负责路由数据的初始化以及管理。
APT
用于生成路由表(路由所需的基本信息)
路由注册
搜集路由信息使用了APT技术,相关细节这里不再讨论,我们主要关注一下APT的生成类,看下主要搜集了哪些信息。
对于Activity
1 |
|
会生成对应的路由信息类
1 | /** |
可以发现搜集的信息主要为路径字符串与路由目标的映射,以及一些路由元数据RouteMeta。
初始化
初始化以ARouter.init()为入口,最后进入到LogisticsCenter.init()。
初始化的过程可以通过插件完成,我们这里只关注不通过插件完成的逻辑,提取我们关心的核心逻辑,代码如下:
1 | // 这里的代码是经过修改与裁剪的,仅为展示逻辑用,与源代码有一定差距 |
可以发现初始化的主要工作就是将APT收集的类信息加载到内存中。
除此之外,_ARouter.afterInit()会在初始化完成后被调用,用以初始化拦截器服务,其具体的功能后面会介绍。
路由跳转
路由跳转最终会进入到_ARouter的navigation(),具体过程可以分解为路由查找与路由跳转两步骤,接下来分析路由跳转的具体过程。
参数传递
参数传递主要通过类Postcard,由它来接收并传递路由跳转过程中需要的参数。换个角度想,要完成路由的功能,我们所需要的信息包含两部分,一部分是路由的目标相关的信息,这些信息在我们开始写业务代码之前就可以预先知道,因此可以通过APT生成,而另外一部分,比如要传给目标路由的参数,这个则是与具体的业务有关的,因此需要我们在业务代码中完成信息传递,而这部分信息的承载者,就是Postcard。具体的细节直接去看Postcard的类结构就行了,这里不再赘述。
路由查找
路由跳转的第一步就是先查找到目标路由,路由查找的具体实现在LogisticsCenter.completion(postcard)中,其核心逻辑可以概括为,从路由信息仓库Warehouse中查找路由信息,然后缓存,便于下次快速访问。其代码可以精简如下:
1 | public synchronized static void completion(Postcard postcard) { |
路由跳转
跳转的最终实现在_navigation()中,该方法的实现可以概括为,对于Activity,跳转意味着跳转到该Activity;对于Service来说,跳转意味着返回之前实例化的单例;对于Fragment来说,意味着实例化Fragment并返回。代码精简如下:
1 | private Object _navigation() { |
作者这里还预留了其他类型,比如方法、CONTENT_PROVIDER等未实现。不过不论如何,这里的逻辑都是获取路由信息,然后跳转并传递。
拦截器
注册与查找拦截器
拦截器是Provider的一种,因此其注册方式也是与其他的Provider一样,都是通过APT生成路由表。
在初始化那一节中提到,_ARouter.afterInit()会在初始化完成后被调用,用以初始化拦截器服务。而这个拦截器服务InterceptorServiceImpl初始化的时候,则会完成拦截器的查找与缓存。具体的逻辑在InterceptorServiceImpl的init()方法中:
1 | public void init(final Context context) { |
调用拦截器
InterceptorServiceImpl本质上就是拦截器的管理器,因此它不仅负责拦截器的注册查找,还负责拦截器的调用。
拦截器的调用发生在LogisticsCenter.completion(postcard)与Arouter._navigation()之间,也就是发生在路由查找与路由跳转之间。
其具体实现都在InterceptorServiceImpl的doInterceptions()方法中。
1 | public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) { |
拦截的主要步骤为依次调用所有拦截器的process()方法,并且使用一个CountDownLatch来计数,然后在onContinue()方法中使计数器-1。假如是在其他线程中执行的拦截,那么拦截器Server的主线程会阻塞,直到所有的拦截器都执行完毕。需要注意的是,CountDownLatch设置了一个超时时间,也就意味着如果异步(与拦截器Server异步)的拦截器没有在限定时间内执行完,那么最外层就回回调超时异常,导致跳转失败。虽然跳转失败了,但是只要拦截器仍然调用了onContinue(),那后续的拦截器逻辑都会走一遍,只不过最后不会再回调最外层的onContinue()。
降级策略
降级策略指的是在路由失败后的客户端的行为。
降级入口
从降级的定义来看,也可以猜到降级的入口应该在路由查找这里。
1 | protected Object navigation() { |
从这里也可以看出降级有两个策略,一个是通过回调单独降级,一个是通过Service的形式进行全局降级,并且单独降级的优先级高于全局降级。
单独降级
NavigationCallback的onLost()方法可以实现单独降级。
全局降级
DegradeService 则被用来实现全局降级。全局降级的注册方式和上面的其他服务是一样的,但是由于Warehouse.providersIndex这个map的key是服务接口的全限定名,因此我们只能实现一个降级处理器,多实现的处理器会被覆盖掉。具体的细节可以参考APT生成的Providers路由表类。