ARouter解析
简介
本篇主要介绍ARouter如何进行路由的,比如Activity、Fragment、服务等
路由的秘密
基本使用
初始化路由之后
1 | ARouter.init(mApplication); |
在需要支持页面路由的页面上添加注解(至少两级)
1 | "/test/activity2") (path = |
在路由时候通过建造者模式构建参数,路由页面
分为以下几种
路由页面
- 普通跳转
1 | ARouter.getInstance() |
- 带参数跳转
1 | ARouter.getInstance() |
其中ARouter提供了丰富的参数类型主要有基本类型、Object、Parceable等,核心原理也是通过Bundle携带传递
- startActivityForResult
比如在TestActivity中
1 | ARouter.getInstance().build("/test/activity2") |
然后在TestActivity中 使用onActivityResult得到数据进行处理,这里跟普通过程一样
- 带回调路由
1 | ARouter.getInstance().build("/xxx/xxx").navigation(this, new NavCallback() { |
路由Fragment
1 | Fragment fragment = (Fragment) ARouter.getInstance() |
路由服务
1 | ARouter.getInstance() |
源码分析
可以看出路由到页面 分为三步
- build 构建 信息邮票(PostCard)
_ARouter # build
1 | /** |
WithXXX 路由参数
navagation 导航
_ARouter # navagation
1 | public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) { |
下面将按照上面的提到三个核心过程进行分析
- 通过path构建路由信息
build是在构建路由信息邮票”PostCard”,从名字看来这就是一张路由邮票,跟网络路由协议传递携带的信息作用一样,通过ARouter这个门面类(Facade)调用实际操控着_ARouter
1 | /** |
这里也体现了作者设计这套框架的扩展性能,这个PathReplaceService
就是让使用者自己可以给path添加扩展。extractGroup就是根据path(/test/activity2)提取group(test),这里就是默认第一个/隔断的字符串,通过这些信息初步
构造路由信息,
1 | protected Postcard build(String path, String group) { |
这样一个具有 path
和group
简单信息的PostCard对象就被构造出来了
- 携带参数
由于是Builder模式,此时构造出postcard之后之后的.WithXXX
实际上实在给PostCard对象填充信息,PostCard对象的Bundle来承载这些信息,
其中 序列化对象SerializationService
转成json存到Bundle中
通过这一步PostCard这个邮票
信息进一步丰满了
- navigation 导航
得到PostCard对象之后回去调用postCard对象的navigation对象,调用函数链如下
1 | PostCard(Arouter.getInstance.build("test/activity2"))——>PostCard#navigation——>ARouter#navigation |
_ARouter#navigation
来到了核心函数 _ARouter#navigation
函数中,这个函数其实是核心路由逻辑的第一道大门,我们越来越接近真相了
1 | protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) { |
这个方法较长 主要分为以下四步
- 首先调用LogisticsCenter.completion完成postcard的补充
- NavigationCallBack的处理
- 拦截器Interceptions的处理
- 开始路由导航
路由导航之前如何将之前获取的postcard信息进行完善?
ARouter.getInstance() .build(“/test/activity2”)时已经返回了一个postcard对象,那么要完善那些信息呢?其实我们可以看出,postcard中只有path和group的信息,目标页面是什么还不明确,因此需要进一步完善信息,核心函数就是上面的LogisticsCenter.completion,这样就体现了框架的重要性,脏活累活交给框架层面,而跟用户打交道的永远都是那么的简洁。
_ARouter#navigationObject navigation(
最后会来到_ARouter#navigationObject navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback))
这个函数负责最终的页面跳转
1 | private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) { |
- Activity
来到ACTIVITY分支,从postcard中拿到目标页面TestActivity.class然后组成intent,然后putExtras,如果是startActivityForResult,这里面就有参数。如果context不是activity,那么就需要另起一个栈Intent.FLAG_ACTIVITY_NEW_TASK进行activity的展示。接下来通过handler发送启动activity的任务。终于找到了熟悉的ActivityCompat.startActivity和ActivityCompat.startActivityForResult,
- Fragment
通过postcard拿到目标页面的Fragment Class,然后实例化这个,还需要兼容fragment,设置Arguments参数之后返回这个Fragment实例
- Provider
这个是用来提供服务的,由于在 完善postCard 核心信息,LogisticsCenter.completion(postcard);
中已经将provider实例化了,这里直接直接get出来就好。后面将会分析LogisticsCenter.completion(postcard)
具体做了哪些工作
LogisticsCenter.completion(postcard)
这个函数就是完善PostCard信息的,postcard是路由信息的容器,到这个函数时候postcard中只有path和group的信息,目标页面是什么还不知道,LogisticsCenter.completion就是填充剩余的关键信息的,b并且是通过按需加载的
,十分重要
1 | public synchronized static void completion(Postcard postcard) { |
流程图如下
这个有一个关键点 WearHouse
- 仓库查找页面节点
首先根据路径信息到WareHouse仓库中查找路由节点信息,其实就是几个map,包含节点、拦截器和组别等信息
1 | RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath()); |
一开始是没有这个节点信息的,所以需要到WareHouse.groupsIndex中找到组别的信息,这里体现了之前提到的分组加载的策略
,这里对应的是test这一组
1 | Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); // Load route meta |
然后通过反射的方式加载这一组类别的映射关系,就是前面提到的按需加载,然后从仓库中删除这个组别信息节点,防止重复加载
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
iGroupInstance.loadInto(Warehouse.routes);
Warehouse.groupsIndex.remove(postcard.getGroup());
其中编译期间已经组成了RouteMeta这个节点信息,包含有目标页面、类型、路径、组别、参数、优先级等信息。可以看到生成之后的信息表并没有直接加载到内存中,而是在第一次访问该组内一个页面时才去加载该组的信息,然后该groupindex移除,防止重复加载
生成的ARouter$$Group$$test
- 填充信息
当第一次没有查找到路由节点之后,要到组别中找到路由信息 load到warehouse中,再次调用本身completion(postcard)
函数.然后执行到else中填充路由信息
- 一些初始化
填充玩信息后,将”服务”实例化,方便后面直接获取,并且将“服务”和fragment设置为绿色通道无需检查,感觉是由于二者本身需要返回一个实例,回调接口NavCallBack只能回调PostCard信息,而且二者近似服务性质,因而不如直接给个绿色通道来的直接。
小结
路由之间跳转到的分析到此基本上告一段落了,其中众多信息都在PostCard中不断完善,然后在LogisticsCenter.completion进行完全填充,更重要的是整体架构关注点分离的设计是非常棒的,编译期间映射信息都下沉到LogisticsCenter与用户层打交道的API都通过ARouter这个门面友好的暴露给用户,我们平时在开发设计中也可以这样学习一下