前言
1. ARouter 简介
- ARouter 是阿里开源的一款帮助 Android App 进行组件化改造的路由框架,是 Android 平台中对页面、服务提供路由功能的中间件,可以实现在不同模块的 Activity 之间跳转
- ARouter 的特点是灵活性强以及帮助项目解耦
- 灵活性强
- 在一些复杂的业务场景下,很多功能都是运营人员动态配置的
- 比如电商系统需要下发一个活动页面,App 事先不知道该活动具体的目标页面,但如果提前做好了页面映射,就可以自由配置了
- 项目解耦
- 随着业务量增长,App 项目代码会越来越多,开发人员之间的协作也会变得越来越复杂,而解决这个问题的方案一般就是插件化和组件化
- 插件化和组件化的前提是解耦,解耦后还要保持页面之间的依赖关系,这时就需要一套路由机制了
2. ARouter 架构概览
API:API 模块由下面几个子模块组成
- launcher:包含了启动器 ARouter
- core:包含物流中心 LogsticsCenter 和仓库 Warehouse 等类
- exception:异常
- thread:拦截器链是放在子线程中执行的,用到了这个模块的 CancellableCountDownLatch
- facede:这个模块包含了 NavigationCallback 和 IInterceptor 等接口
- utils:包含了 ARouter 自定义的日志打印器等工具类
- base:只有一个用于保存拦截器的 UnitqueKeyTreeMap
Compiler
- ARouter 的 Compiler 模块是用于生成路由表的,@Autowired、@Interceptor 和 @Route 注解对应的注解处理器分别是是 AutowiredProcessor、InterceptorProcessor 以及 RouteProcessor
Plugin
- 如果我们使用了 ARouter 的路由表加载插件,那这个路由表就会由 ARouter Register 插件加载
Annotation
- 这个模块比较简单,只包含了一些注解和枚举类
3. ARouter 基本用法
添加依赖与配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// Kotlin 注解处理插件
apply plugin: 'kotlin-kapt'
// Kotlin 注解处理选项
kapt {
// 参数:模块名
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
// 依赖
dependencies {
// 替换成最新版本,需要注意的是 api 要与 compiler 匹配使用
// 均使用最新版本可以保证兼容
compile 'com.alibaba:arouter-api:1.5.0'
kapt 'com.alibaba:arouter-compiler:1.2.2'
// 如果要在 Activity 之间传递序列化对象,就要使用 Json 解析
implementation 'com.alibaba:fastjson:1.2.48'
}声明路径
1
2
3
4
class GoodsDetailsActivity : AppCompatActivity() {
// ...
}- 使用 ARouter 要用 @Route 注解声明跳转目标的路径,在这里要注意,最前面的斜杠是不能少的,而且路径至少有量级
- group 是可选的,ARouter 内部会对 path 进行分组,以上面这段代码为例,如果不传 group 的话,那 ARouter 会把 goods 作为该路径的 group ,否则 taobao 就是该路径所属的 group
初始化 ARouter
1
2
3
4
5
6
7
8
9
10
11
12
13private fun initARouter() {
if(BuildConfig.DEBUG) {
// 打印日志
ARouter.openLog()
// 开启调试模式(如果在 InstantRun 模式下运行
// 线上版本需要关闭,否则有安全风险)
ARouter.openDebug()
}
// 尽可能早初始化,推荐在 Application 中初始化
ARouter.init(application)
}- 打印日志和开启调试模式必须写 在
init()
之前,否则这些配置在初始化过程中将无效
- 打印日志和开启调试模式必须写 在
跳转
1
2
3
4
5// 1. 应用内简单的跳转
ARouter.getInstance()
// 构建明信片,设定 path 与 group
.build("/goods/details", "taobao")
.navigation()- 在跳转时,我们也可以传 group,比如这个例子中传了 taobao,那就会跳转到 taobao 分组下的商品详情页,不传的话,就会跳到 goods 分组下的详情页
一. 明信片 Postcard
- 当我们调用
ARouter.getinstance().build()
时,其实是在创建一个明信片 Postcard 对象,withXXX()
和navigation()
方法就是它的方法,Postcard 的navigation()
方法最终调用的是 ARouter 的navigation()
方法 - 按 Postcard 的注释来说,它是路线图的容器,我们可以把它看做是一张包含了收件人信息以及特定内容的明信片
- Postcard 继承了 RouteMeta,RouteMeta 是路由表的内容,而 Postcard 则包含了在跳转时的传参和动画等信息
1. RouteMate
RouteMate 示意图
RouteMeta 包含了以下字段
路线类型:路线类型 RouteType 是一个枚举类,有下面几种类型(其中 Service、Broadcast 和 Method 是未实现的)
- Activity
- Service
- Provider:也就是自定义服务 IProvider
- ContentProvider
- Fragment
- Broadcast
- Method
- Unknown:未知路线
路线原始类型
- 路由原始类型 rawType 的类型为 Element,关于 Element ,在后面会进一步讲解,这里只需要知道 Element 中包含了跳转目标的 Class 信息,是由路由处理器 RouteProcessor 设定的
终点
- 终点 destination 就是声明了 @Route 的跳转目标的 Class ,比如目标 Activity 和 Fragment 的 Class,这个信息也是由 RouteProcessor 设定的
路径和路线组
- 如果我们在 @Route 中只设定了路径,比如 path = /goods/details ,那么 goods 就是 group ,details 就是路径 path
- 如果我们设置了 @Route 的 group 的值,比如 group = taobao ,那么 path 的 group 就是 taobao
优先级
- 优先级在 @Route 中无法设定,是给拦截器用的,priority 的值越小,拦截器的优先级就越高
- 拦截器链的实现类为 InterceptorServiceImpl,它在调用拦截器的 onInteceptor() 方法时,就是按照 priority 的顺序来获取拦截器,然后逐个调用的
标志:这个 extra 是路由文档 RouteDoc 的标志,文档中包含了路由和服务相关的信息 ,默认不会生成对应的文件,如果想生成的话,可以在注解处理参数中设置生成文档
添加参数:如果我们想查看路由文档,可以 AROUTER_MODULE_NAME 后面添加
AROUTER_GENERATE_DOC: "enable"
文档路径:
build/generated/source/apt/(debug or release)/com/alibaba/android/arouter/docs/arouter-map-of-${moduleName}.json
,路由文档的大致内容如下
参数类型
- paramsType 也就是参数类型,对于我们跳转时设定的参数,ARouter 会根据不同的类型给它们一个枚举值,然后取值时,再根据不同的类型调用 Intent 的 getXXXExtra() 等方法
2. Postcard
Postcard 示意图
Postcard 中包含如下字段
uri
1
2
3
4val uri = Uri.parse("demo://www.xxx.com/moduleA/second?name=老王")
ARouter.getInstance()
.build(uri)
.navigation()- 在 ARouter 中,我们可以用 URI 作为路径跳转,ARouter 会用路径替换服务 PathReplaceService 替换路径,这个服务没有默认实现,如果我们需要为不同的协议和主机替换不同的路径时,就要自己实现这个服务
- 如果我们没有实现这个服务,那 scheme 和 主机地址等信息是没有意义的,ARouter 默认情况下只会对路径和参数进行解析,在上面的例子中,路径就是
moduleA/second
,参数为name=老王
tag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class TestInterceptor : IInterceptor {
override fun init(context: Context?) {
// 拦截器的初始化,会在 sdk 初始化的时候调用该方法,仅会调用一次
}
override fun process(postcard: Postcard?, callback: InterceptorCallback) {
callback.onInterrupt(RuntimeException("有内鬼,停止交易"));
}
}
ARouter.getInstance()
.build(path)
navigation(this, object : NavigationCallback) {
// 跳转中断
override fun onInterrupt(postcard: Postcard?) {
// 有内鬼,停止交易
val errorMsg = postcard?.tag
}
}- tag 用于在 NavigationCallback 的
interrupt()
方法中获取异常信息 - 在拦截器链 InterceptorServiceImpl 中,当我们在自定义的拦截器中调用
onInterrupt()
方法时,InterceptorServiceImpl 会创建一个 HandlerException ,并把它作为 Postcard 的 tag ,然后监听跳转结果的地方,就能在onInterrupt()
方法中通过获取 Postcard 的 tag 信息来获取异常信息 - 我们在拦截器中传入的 exception 为空的话,那么
HandlerException()
的 message 默认为 “No Message.”
- tag 用于在 NavigationCallback 的
mBundle
- 我们调用
withString()
等方法设置要传递给跳转目标的数据时,这个数据就是放在 mBundle 中的
- 我们调用
flags
- 我们调用
withFlag()
设定 Activity 的启动标志时,这个标志就会赋值给 flags 字段
- 我们调用
timeout
- 拦截器链处理跳转事件是放在 CountDownLatch 中执行的,超时时间默认为 300 秒,也就是 5 分钟,所以我们在拦截器中不要进行时间太长的耗时操作
provider
- 当我们实现了自定义服务时,参数注解处理器 AutowiredProcessor 会为各个路径创建一个实现注射器 ISyringe 接口的类,在这个类的
inject()
方法中,调用了ARouter.getInstance().navigation(XXXService.class)
,当 LogisticsCenter 发现这是一个 Provider 时,就会通过反射创建一个 Provider 实例,然后设置给 Postcard ,再进行跳转
- 当我们实现了自定义服务时,参数注解处理器 AutowiredProcessor 会为各个路径创建一个实现注射器 ISyringe 接口的类,在这个类的
greenChannel
- 所谓绿色通道,就是不会被拦截器链处理的通道,自定义服务 IProvider 和 Fragment 就是走的绿色通道
- 如果我们想让某个跳转操作跳过拦截器,可以在
navigation()
前调用greenChannel()
方法
serializationService
- 当我们调用
withObject()
方法时,ARouter 就会获取我们自己自定义的序列化服务 SerializationService,然后调用该服务的object2Json()
方法,再把数据转化为 String 放入 bundle 中
- 当我们调用
二. ARouter 路由表生成原理
1. 注解处理流程
- 关于 Android Gradle 的 和 Javac 这里不会展开讲,在这里我们只需要理解在对 @Route 等注解处理前,是由 Android Gradle 的 AndroidJavaCompiler 来发起编译操作,然后让 Javac 去调用 RouteProcessor 等注解处理器对注解进行处理的
2. 路由解析流程
获取路由元素
- 这里的元素指的是 javax 包中的 Element ,Element 表示 Java 语言元素,比如字段、包、方法、类以及接口
process()
方法会接收到 annotations 和 roundEnv 两个参数,annotations 就是当前处理器要处理的注解,roundEnv 就是运行环境 JavacRoundEnvironment- JavacRoundEnvironment 有一个
getElementsAnnotatedWith()
方法,RouteProcessor 在处理注解时首先会用这个方法获取元素
创建路由元信息
- 这里说的路由元信息指的是 RouteMeta,RouteProcessor 会把声明了 @Route 注解的的 Activity、Provider、Service 或 Fragment 和一个 RouteMeta 关联起来
- 当元素类型为 Activity 时,RouteProcessor 会遍历获取 Activity 的子元素,也就是 Activity 的成员变量,把它们放入注入配置 RouteMeta 的 injectConfig 中,当我们配置了要生成路由文档时,RouteProcessor 就会把 injectConfig 写入到文档中,然后就对元信息进行分组
把路由元信息进行分组
- 在 RouteProcessor 中有一个 groupMap,在 RouteMeta 创建好后,RouteProcessor 会把不同的 RouteMeta 进行分组,放入到 groupMap 中
- 拿路径
/goods/details
来说,如果我们在 @Route 中没有设置 group 的值,那么 RouteProcessor 就会把 goods 作为 RouteMeta 的 group
生成路由表
当 RouteProcessor 把 RouteMeta 分组好后,就会用 JavaPoet 生成 Group、Provider 和 Root 路由文件,路由表就是由这些文件组成的,JavaPoet 是 Square 开源的代码生成框架
生成路由文件后,物流中心 LogisticsCenter 需要用这些文件来填充仓库 Warehouse 中的 routes 和 providerIndex 等索引,然后在跳转时根据 routes 和索引来跳转
关于 LogisticsCenter 和 Warehouse 在后面会讲,下面我们来看下路由文件的内容
RouteProcessor 生成的路由文件位于
build/generated/source/kapt/(debug/release)/com/alibaba/android/arouter/routes
以 ARouter 示例项目中的一个路由文件为例,RouteProcessor 创建的 RouteMeta 会转化为下面这样的文件
- 其他的路由文件也是大同小异的,所有内容都是由 RouteProcessor 填充的
三. ARouter 跳转原理
当我们调用 Postcard 的
navigation()
方法时,Postcard 会调用 ARouter 的navigation()
方法,然后 ARouter 才会去加载路由表,所以我们来看下navigation()
的处理流程ARouter 的
navigation()
方法有下面两种重载navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback)
navigation(Class<? extends T> service)
第一种重载是进行跳转的,第二种重载是用来创建服务的,下面我们来看第一种重载的实现
1. 预处理服务
实现预处理服务
- 预处理服务可以让我们在 ARouter 进行跳转前,根据 PostCard 的内容判断是否要独立地对这次跳转进行处理,是的话则在
onPretreatment()
中返回 false 即可
- 预处理服务可以让我们在 ARouter 进行跳转前,根据 PostCard 的内容判断是否要独立地对这次跳转进行处理,是的话则在
预处理服务处理流程
- 在
navigation()
中,首先会调用预处理服务的onPretreamtn()
方法,判断是否要继续往下处理,如果返回结果为 false ,则不再往下处理,也就是不会进行跳转等操作
- 在
2. 完善明信片
获取路由元信息
- 在 ARouter 初始化时,会把 LogisticsCenter 也进行初始化,而 LogisticsCenter 的初始化方法中,会读取 RouteProcessor 创建好的路由表,然后放到对应的索引 index 中
- 有了索引,当 ARouter 调用 LogisticsCenter 的
completion()
方法时,就可以用索引从 Warehouse 的 routes 中获取路由元信息 - 如果 LogisticsCenter 根据索引查找不到对应的 RouteMeta,那就说明 routes 还没有被填充,这时 LogisticsCenter 就会获取 group 的 RouteMeta,然后把 group 下的路径填充到 routes 中,然后再调用一次
completion()
,这时就可以取填充明信片的信息了 - 索引是在 LogsticsCenter 初始化的时候加载的,后面在路由表加载原理的时候会讲到
填充明信片信息
- 我们在调用
ARouter.getInstance().build()
方法时,就是创建了一张 Postcard,但是这张 Postcard 的信息是不完整的 - 比如 Postcard 中有一个 destination 字段,destination 表示跳转目标的 Class 信息,跳转 Activity 要用 Intent,destination 就是 Intent 的构造函数的第二个参数
- 而 LogisticsCenter 就要负责把从路由表获取到的 destination 信息填充到这张明信片中,有了一张信息完整的明信片,才能进行后续的跳转操作
- 我们在调用
初始化 Provider
- 填充完了 Postcard 的信息后,LogisticsCenter 会根据 Postcard 的类型来做不同的操作,如果是 Provider 的话,就会调用 Provider 的初始化方法,并且把 Postcard 设为绿色通道
- 如果是 Fragment 的话,那就只把 Postcard 设为绿色通道,如果是其他类型,则不设为绿色通道,这里说的绿色通道,其实就是说 Provider 和 Fragment 是跳过拦截器链的
3. 降级策略
- 所谓的降级策略,其实就是跳转失败时,我们能够跳转到别的页面,比如一个跳转失败提示页
- 假如 ARouter 在完善明信片信息的过程中遇到了异常
降级策略处理流程
- 调用完预处理服务后,
navigation()
就会通过物流中心 LogisticsCenter 来填充 PostCard 内容,如果在填充过程中遇到了异常,就会调用降级服务
- 调用完预处理服务后,
自定义降级策略
- 在自定义降级策略时,要注意 context 可能会空,要使用 Context?
4. 拦截器
- 拦截器可以用来在跳转过程中处理事件,比如做登陆检查,拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行
实现拦截器
- 实现拦截器时,我们要调用
onContinue()
或onInterrupt()
方法,至少需要调用其中一种方法,否则不会继续路由 onContinue()
:这个方法表示处理完成,交换控制权给 ARouteronInterrupt()
:当我们觉得有问题时,可以用onInterrupt()
方法,传一个异常,以中断路由流程
- 实现拦截器时,我们要调用
拦截器处理流程
navigation()
在完善 Postcard 信息后,就会判断该 Postcard 是否通过绿色通道来处理,绿色通道就是不经过拦截器链的通道- 在 LogisticsCenter 的
completion()
中,中会把路由类型为 Provider 和 Fragment 的路线设为绿色通道,如果我们想让目标页面跳过拦截器链,就可以在navigation()
方法前调用greenChannel()
方法
5. 按类型跳转
- 当处理完拦截器后,
navigation()
中就会调用navigation()
方法,这也是具体进行跳转的方法。 - 在这个方法中,会根据 Postcard 的路由类型 RouteType 来判断怎么跳转
Activity
- 当 RouteType 为 Activity 时,启动 Activity 的流程和我们平时启动 Activity 的流程是一样的,创建 Intent、传入 destination、设置 fragment 和重写动画等,最终调用
startActivity()
启动目标页面
- 当 RouteType 为 Activity 时,启动 Activity 的流程和我们平时启动 Activity 的流程是一样的,创建 Intent、传入 destination、设置 fragment 和重写动画等,最终调用
Fragment/Broadcast/ContentProvider
- 当跳转目标为 Fragment、Broadcast 或 ContentProvider 时,会通过 destination 用反射创建实例,如果是 Framgent ARouter 还会为它设置要传递给目标 Fragment 的参数,然后返回实例
Provider
- 如果跳转目标为 Provider,也就是自定义服务的话,就对应了后面讲 ARouter 自定义服务时讲的“通过依赖查找发现服务”
6. 跳转回调
在调用
navigation()
跳转时,我们可以在navigation()
中传入 NavigationCallback 监听跳转过程中发生的事件onLost()
:无法查找到跳转目标onFound()
:找到了跳转目标onInterrupt()
:拦截器中断了跳转onArrival()
:已打开跳转目标除了 NavigationCallback ,我们也可以用 NavCallback 监听跳转中发生的事件,NavCallback 是 ARouter 中实现了 NavigationCallback 的一个抽象类,使用 NavCallback 不会强制要求我们重写所有方法,只要求重写
onArrival()
方法
四. ARouter 路由表加载原理
- 所谓的加载路由表,其实就是加载 RouteProcessor 生成的类文件。
- 在我们调用 ARouter 的
init()
方法时,ARouter 会调用 LogisticsCenter 的init()
方法,在 LogisticsCenter 的init()
方法中,会判断当前路由表加载方式是否为插件,不是的话则从 Dex 中加载路由表,是的话则由插件从 Jar 中加载路由表
1. 从 Dex 中加载路由表
读取 Dex 文件
- LogisticsCenter 发现没有用插件加载路由表时,就会用 ClassUtils 读取路由表。
- 这里说的路由表,其实就是 RouteProcessor 生成好的类文件类名,而读取 Dex 文件的方式,就是从源码目录(applicationInfo.sourceDir) 中读取 base apk 的路径,然后用这个路径构建一个 DexFile(path)
从 Dex 文件中读取路由表
- ClassUtils 用 DexFile 读取 apk 中的类信息,然后判断类的包名是否为 “com.alibaba.android.arouter.routes” ,是的话说明这是 ARouter 的注解处理器生成的路由文件,把匹配上的类加入列表中,然后把列表返回给 LogisticsCenter
把路由表保存到本地
- 当 LogisticsCenter 从 ClassUtils 中获取到注解处理器生成的类名时,就会把这些类名保存 SharedPreferences 中,下次就根据 App 版本判断,如果不是新版本,就从本地中加载类名,否则就用 ClassUtils 读取类名
把路由信息保存到索引中
- 当 LogisticsCenter 把路由表保存到 SharedPreferences 后,就会根据类名的后缀判断类是 IRouteRoot 、IInterceptorGroup 还是 IProviderGroup ,然后根据不同的类把类文件的内容加载到索引中
2. 从 Jar 中加载路由表
如果我们想缩短 ARouter 的初始化时间,可以用 ARouter 的 Gradle 插件,这个插件能自动加载路由表,这样 ARouter 初始化的时候就不需要读取类的信息,从而缩短初始化时间
Register 插件从 Jar 文件加载路由表的流程如下
PluginLaunch.apply()
- 当我们运行 App 时,Gradle 就会调用我们依赖的 ARouter Register 插件,这个插件的执行的起点就在 PluginLaunch.apply() 中,PluginLaunch 判断了只有在运行的项目为 Applicaiton 时,才会加载路由表信息
BaseExtention.registerTransform()
- Android Gradle 插件包含了一个 Transform API,这个 API 允许第三方插件在编译后的类文件转换为 dex 文件前做处理操作,而 ARouter 的 Register 插件就实现了一个 RegisterTransform
RegisterTransform.transform()
- 当 Gradle 的任务管理器 TaskManager 执行 TransformTask 时,就会执行 RegisterTransform 的
transform()
方法 - 在 transform() 方法中,会接收到一个 TaskManager 传过来的 TransformInput 集合,通过 TransformInput 可以获取到 Gradle 为我们项目生成的 Jar 和 Class 文件,包括 RouteProcessor 生成的文件
- 当 Gradle 的任务管理器 TaskManager 执行 TransformTask 时,就会执行 RegisterTransform 的
ScanClassVisitor.visit()
- 当 RegisterTransform 获取到了 Class 文件后,就会用 ScanUtils 中的 ScanClassVisitor 访问 Class 中的字节码数据,包括 Class 的包名和类名
- ScanClassVisitor 是 ClassVisitor 的子类,ClassVisitor 可以改变修改字节码,当 ScanClassVisitor 发现当前 Class 实现了 IRouteRoot、IIntercetorGroup 或 IProviderGroup 接口时,这三个接口都是就会把当前 Class 的类名添加到 ScanSetting 的 classList 中
RegisterCodeGenerator.insertInitCodeIntoJarFile()
当 RegisterTransform 把 ScanSetting 中的 classList 初始化完后,就会用代码生成器 RegisterCodeGenerator 插入代码到 Jar 文件中
在 RegisterCodeGenerator 的
insertInitCodeIntoJarFile()
方法中,会把 Jar 文件转化为 JarFile 对象,然后获取到 JarFile 中的 JarEntry ,找到 LogisticsCenter,然后把路由表插入到 LogisticsCenter 的loadRouteMap()
方法中,比如下面这样Jar 文件路径:
build/intermediates/transforms/com.alibaba.arouter/debug/41.jar
五. ARouter 进阶用法与注意事项
1. 传参
2. 解析参数
@JvmField
- 这里需要注意的是,如果 Activity 或 Fragment 是用 Kotlin 写的,那字段就要加上 @JvmField ,以提供
getter()
和setter()
给 ARouter 使用
- 这里需要注意的是,如果 Activity 或 Fragment 是用 Kotlin 写的,那字段就要加上 @JvmField ,以提供
默认值不能为空
- 这里的 key 的值会被取做默认值,不能为空,否则会出现空指针异常
- 因为 ARouter 在用 Intent 的
getLongExtra()
等方法获取参数时,这些方法默认值不是包装类型,如 Long ,而是基本类型,如 long
withObject()
- 使用
withObject()
传递 List 和 Map 时,接收该对象的地方不能标注具体的实现类类型,应仅标注为 List 或 Map,否则会影响序列化中类型的判断, 其他类似情况需要同样处理
- 使用
查看异常
- 如果你发现接收不到你想要的参数时,可以在 AutowiredServiceImpl 的
autowired()
方法中打个断点看下遇到了什么异常
- 如果你发现接收不到你想要的参数时,可以在 AutowiredServiceImpl 的
查看编译日志
- 如果在使用 ARouter 的过程中,出现了编译失败但是不知道原因时,可以用命令查看详细的编译日志
gradle aseembleDebug --stacktrace
- 如果在使用 ARouter 的过程中,出现了编译失败但是不知道原因时,可以用命令查看详细的编译日志
3. 实现序列化服务
- ARouter 允许我们设置序列化服务,如果需要传递自定义对象,那只需要新建一个实现 SerializationService 的类,并加上 @Route注解
- 这里的 yourservicegroupname ,指的是我们可以给服务设定不同的分组
4. 自定义服务
声明接口
实现接口
通过依赖注入发现服务(推荐)
- helloService 和 helloService2 就是通过依赖注入的方式发现服务的,也就通过注解标注字段即可使用,无需主动获取。
- byType:不设置 name 属性的话,会默认使用 byType 的方式发现服务,helloService 就是 byType。
- byName:Autowired 注解中标注 name 之后,将会使用 byName 的方式注入对应的字段。当同一接口有多个实现的时候,必须使用byName的方式发现服务,helloService2 就是 byName
- helloService 和 helloService2 就是通过依赖注入的方式发现服务的,也就通过注解标注字段即可使用,无需主动获取。
通过依赖查找发现服务
- 主动发现服务并使用,helloService3 是 byName ,helloService4 是 byType
5. 通过 URL 跳转
如果我们想让应用直接处理外部 URI,只要在清单文件中进行配置,再把 url 传递给 ARouter 即可
设定 host:首先在 Manifest 中声明 Activity 的 action 和 category ,并且在 data 标签中添加主机和协议
监听 Scheme:然后新建一个Activity用于监听Scheme事件,直接把 url 传递给 ARouter 即可
6. 设置转场动画
7. 获取 Fragment
- 获取 Fragment 时要注意,当找不到对应路径的 Fragment 时,会返回 null,所以这里用空安全的 as?
六. 其他
1. ARouter 参数生成与加载
- 没有讲参数的生成与加载流程,这个流程和 RouteProcessor 生成路由表的原理类似
- 对于参数,ARouter 会用 AutowiredProcessor 来生成参数表,这个表的类实现了注射器 ISyringe 接口
- 而我们调用的
ARouter.inject()
方法,就是在加载参数表的内容