一、先一句话根本定义
IProvider 就是 ARouter 官方规定的【服务接口父接口】所有想要跨模块暴露功能、对外提供服务的接口,必须继承它。
java
运行
public interface IProvider {
// 生命周期初始化方法
void init(Context context);
}
它里面就一个空方法 init() ,本身没业务代码,纯粹是一个标记 + 规范。
二、为什么继承 IProvider,就能对外提供接口?
1. ARouter 的底层扫描规则(核心原因)
ARouter 在编译期(打包时)会做扫描:
所有实现了
IProvider子接口的实现类,并且加了@Route(path="...")我全部收集起来,存入路由注册表。
也就是说:IProvider = ARouter 识别「服务」的唯一标记
- 普通接口:ARouter 不认识
- 继承
IProvider的接口:ARouter 认定这是对外服务
2. 原理:路由注册表
你每次写
java
运行
@Route(path = "/service/car_api")
public class CarProviderImpl implements ICarProvider {
ARouter 编译器会自动生成代码,把:路径 /service/car_api ↔ CarProviderImpl 实现类
绑定存入路由表。
等到你调用:
java
运行
ARouter.getInstance().build("/service/car_api").navigation();
ARouter 就去查表 → 找到实现类 → 创建单例对象 返回给你。
3. 为什么非要继承 IProvider?不能直接用普通接口?
如果没有 IProvider:
- ARouter 分不清你这个类是跳转页面、还是普通工具类、还是服务
- 无法统一管理单例、无法统一初始化、无法统一生命周期
- 无法做组件化解耦
IProvider 就是一个身份牌
拿到这个身份牌 = 我是对外服务,可以跨模块调用
三、完整一套结构(你项目 1:1 对应)
1. 顶层父接口(ARouter 自带)
java
运行
public interface IProvider {
// 服务初始化时回调,框架自动调用
void init(Context context);
}
2. 业务子接口(暴露对外方法,放在 base 公共模块)
java
运行
// 车机服务接口,所有模块都能依赖 base,但是不依赖车机模块
public interface ICarProvider extends IProvider {
// 对外提供:监听Tab切换
LiveData<Pair<Integer, Object>> getCarTab();
// 对外提供:切换Tab
void switchTab(int index);
}
3. 接口实现类(在车机业务模块内部,不对外暴露)
java
运行
// 只有车机模块自己知道这个实现类
@Route(path = RouterCarPath.Provider.CAR_API)
public class CarProviderImpl implements ICarProvider {
@Override
public void init(Context context) {
// 框架自动初始化,你不用管
}
@Override
public LiveData<Pair<Integer, Object>> getCarTab() {
// 真实业务逻辑
return carTabLiveData;
}
}
4. 其他模块调用(完全不依赖车机模块)
java
运行
ICarProvider carProvider = (ICarProvider) ARouter.getInstance()
.build(RouterCarPath.Provider.CAR_API)
.navigation();
// 直接调用方法,监听Tab
carProvider.getCarTab().observe(xxx);
四、IProvider 到底实现了什么能力?(4 大核心作用)
1. 组件化完全解耦(最重要)
- A 模块要用 B 模块功能
- A 完全不用依赖 B 的 module
- 只依赖 base 里的接口
ICarProvider - 实现类藏在 B 模块内部,外部完全看不见
这就是大厂组件化架构的核心。
2. 全局单例
ARouter 拿到的 Provider 默认全局单例整个 App 只有一个实例,不用你自己写单例、不用 Dagger、不用 Hilt。
3. 统一初始化生命周期
所有 Provider 的 init(Context) 方法App 启动时 ARouter 自动调用你不用在 Application、不用在 StartUpTask 手动初始化。
4. 统一服务管理
所有跨模块能力全部收拢到 Provider
跳转页面用 @Route
调用功能服务 全部用 IProvider
五、你最疑惑的灵魂问题:
为什么它就可以对外提供接口?
我用大白话总结成 3 句你永远忘不掉:
IProvider是 ARouter 官方规定的【服务标识接口】
- 只要接口继承它,ARouter 就认定这是对外服务。
- 配合
@Route注解,编译期自动生成路由映射表
- 把路径和实现类绑定,外部只需要填路径就能拿到对象。
- 接口在公共基础层,实现在业务内层
- 外部只看得见接口,看不见实现,完美解耦,实现跨模块调用。
六、结合你刚刚的代码完整串讲
java
运行
// 1. 根据路径查表,拿到车机服务的单例实例
ICarProvider carProvider = (ICarProvider) ARouter.getInstance()
.build(RouterCarPath.Provider.CAR_API)
.navigation();
// 2. 调用接口里暴露的方法,拿到可观察的Tab事件
// 因为ICarProvider继承了IProvider,所以才能被ARouter获取到
carProvider.getCarTab()
// 3. 生命周期安全监听
.observe(container.getViewLifecycleOwner(), pair -> {
// Tab切换回调
});
七、和你之前所有知识点串联(全部打通)
@StartUpTask:App 启动自动初始化各个 SDKIProvider:模块之间对外暴露服务、跨模块拿对象Consumer<Fragment>:Fragment 创建完成回调任务- Navigation 动态注册:拿到服务后动态添加页面、动态跳转
- LiveData.observe:监听服务内的数据变化(Tab 切换)
- Maybe:获取服务有可能为空、异常的场景封装
八、终极精简背诵版(面试直接说)
-
IProvider 是 ARouter 服务接口的父接口,仅作为标记规范
-
子接口继承它 + 实现类加
@Route,即可被 ARouter 注册为服务 -
外部模块通过路径
navigation()即可获取实例,无需模块依赖 -
作用:组件化解耦、跨模块功能调用、全局单例、统一初始化
-
区别:
@Route用于 页面跳转 (Fragment/Activity)IProvider用于 功能服务调用 (方法)