arouter-api version : 1.4.1
前言
之前对 ActivityRouter 的源码做了一次分析,相信大家对路由框架已经有一个大概的理解了。
而今天给大家分析一下 ARouter 。大家在项目组件化的过程中,可能绝大多数的开发者都会使用 ARouter 来作为项目的路由框架。毕竟 ARouter 是阿里出品,优点自然不必多说了。
所以在平常使用的过程中,不仅仅要做到会用,还要深入了解一下 ARouter 的内部原理。
本次 ARouter 的解析分为三部分:
- 对 IRouteRoot 页面跳转进行源码解析;
- 对 IInterceptorGroup 拦截器进行源码解析;
- 对 @Autowired 自动注入进行源码解析;
- 对 ARouter 的 arouter-compiler 进行源码分析;
- 对 ARouter 的 arouter-register 进行源码分析;
本篇是 ARouter 系列的第一篇,下面就对 IRouteRoot 页面跳转进行详细解析。
ARouter 源码
使用 ARouter 的时候,都需要初始化
1 | if (isDebug()) { |
源码分析的入口,就在 ARouter.init 里
1 | public static void init(Application application) { |
源码上可以看到,ARouter 的内部其实是 _ARouter 在起作用,ARouter 只是把 _ARouter 再做了一层包装。那么我们就跟进 _ARouter 的 init 方法。
1 | protected static synchronized boolean init(Application application) { |
最重要的一句代码还是 LogisticsCenter.init(mContext, executor)
,其中 executor 是线程池。
那么问题来了, LogisticsCenter 是干什么的呢?
* LogisticsCenter contains all of the map.
*
* 1. Creates instance when it is first used.
* 2. Handler Multi-Module relationship map(*)
* 3. Complex logic to solve duplicate group definition
根据官方的注释,LogisticsCenter 是包含了所有的映射,处理跨模块的映射关系以及匹配路由等。
所以根据之前 ActivityRouter 的经验猜测得到,LogisticsCenter 的 init 方法里面,肯定会去加载路由,并建立关系。
1 | public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException { |
LogisticsCenter 的 init 方法的代码基本上都可以看得懂,其中 ClassUtils.getFileNameByPackageName
是我们值得探究的地方。这句代码主要做的事情就是从 dex 中遍历 class 找到 arouter-compiler 生成的类集合。具体的分析我们到最后面再讲,这里先埋个伏笔。
接着往下看,我们知道,routerMap 中的 className 都是 arouter-compiler 在编译期生成的,那我们先来看看生成的类长什么样
1 | /** |
ARouter 的路由会分组加载,比如当前有 /test/abc 和 /test/def 两个路由,那他们同属于 /test 这个组。所以在 Warehouse.groupsIndex 中存放的 key 是路由组名,value 是对应组路由类。查找路由的时候也是根据组名 key ,再找到组路由类 value 中查找匹配的路由。
1 | /** |
可以看到路由相关的参数配置被构造成了一个 RouteMeta 对象。RouteMeta 类如下所示:
1 | public class RouteMeta { |
到这里,加载路由的部分就完成了,剩下的就是跳转路由了。
跳转路由的通常操作:
ARouter.getInstance().build("/test/abc").navigation();
那先看一下 ARouter 的 build 方法
1 | public Postcard build(String path) { |
里面调用的是 _ARouter 的 build 方法。
1 | protected Postcard build(String path) { |
PathReplaceService 是官方给我们预留的口子,用来对 path 做预处理。如果你有需求来对 path 做统一的预处理,那么直接实现 PathReplaceService 即可。
我们接着跟进,看下 _ARouter.build(String path, String group)
方法
1 | protected Postcard build(String path, String group) { |
发现在 build(String path, String group)
中直接创建了一个 Postcard 对象并返回。Postcard 类是继承了 RouteMeta ,额外添加了一些其他的信息。
有了 Postcard 之后,直接调用 navigation 进行跳转。
1 | public Object navigation(Context context, NavigationCallback callback) { |
Postcard 的所有 navigation 方法最后都会调用 ARouter 的 navigation 这个方法。
1 | public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) { |
最后还是调用了 _ARouter.navigation
1 | protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) { |
上面的代码基本上都写了注释,大家应该都能看懂。
我们重点来关注下 LogisticsCenter.completion(postcard);
1 | public synchronized static void completion(Postcard postcard) { |
至此,整个路由跳转的流程就讲完了,大致的流程可以分为
- 加载路由映射
- 根据 path 构造出 Postcard 对象
- 区分 Postcard 的 type 来实现跳转
番外
前面说过,ARouter 会在 dex 中寻找 arouter-compiler 生成的类。那我们最后来看看是怎么实现的。
1 | public static Set<String> getFileNameByPackageName(Context context, final String packageName) throws PackageManager.NameNotFoundException, IOException, InterruptedException { |
我们再来看下 getSourcePaths 方法,看看它是怎么找 dex 文件路径的
1 | public static List<String> getSourcePaths(Context context) throws PackageManager.NameNotFoundException, IOException { |
更多的细节有兴趣的同学可以自己回去看,这里因为篇幅的原因就不过多讲这些了。
那么今天就到这里结束了,关于 ARouter 系列的更多源码解析,可以看接下来的两篇博客。
bye