路由框架
问题
什么是路由框架?ARouter 的原理是什么?
答案
路由框架的作用
在组件化项目中,模块间不能直接引用 Activity 类。路由框架通过 URL → Activity/Fragment/Service 的映射实现解耦跳转。
ARouter 核心原理
编译期
// 使用注解标记目标
@Route(path = "/profile/detail")
class ProfileDetailActivity : AppCompatActivity()
// APT 生成路由表类(伪代码)
class ARouter$$Group$$profile : IRouteGroup {
override fun loadInto(atlas: MutableMap<String, RouteMeta>) {
atlas["/profile/detail"] = RouteMeta(
path = "/profile/detail",
destination = ProfileDetailActivity::class.java,
type = RouteType.ACTIVITY
)
}
}
运行时
// 跳转
ARouter.getInstance()
.build("/profile/detail")
.withString("userId", "123")
.navigation()
// 带回调
ARouter.getInstance()
.build("/profile/detail")
.navigation(context, object : NavigationCallback {
override fun onFound(postcard: Postcard) { /* 找到路由 */ }
override fun onLost(postcard: Postcard) { /* 路由不存在 */ }
override fun onArrival(postcard: Postcard) { /* 跳转完成 */ }
override fun onInterrupt(postcard: Postcard) { /* 被拦截 */ }
})
拦截器(登录检查)
@Interceptor(priority = 1, name = "LoginInterceptor")
class LoginInterceptor : IInterceptor {
override fun process(postcard: Postcard, callback: InterceptorCallback) {
if (postcard.extra == LoginRequired && !UserManager.isLoggedIn) {
// 拦截,跳到登录页
ARouter.getInstance().build("/login/main").navigation()
callback.onInterrupt(null)
} else {
callback.onContinue(postcard)
}
}
override fun init(context: Context) {}
}
Navigation Component 替代方案
Jetpack Navigation 也支持模块化导航,通过 Deep Link 实现跨模块跳转:
feature-profile/navigation.xml
<navigation>
<fragment
android:id="@+id/profileFragment"
android:name="com.example.profile.ProfileFragment">
<deepLink app:uri="app://profile/{userId}" />
</fragment>
</navigation>
feature-home 跳转
val uri = Uri.parse("app://profile/123")
findNavController().navigate(uri)
常见面试问题
Q1: ARouter 和 Jetpack Navigation 如何选择?
答案:
| 维度 | ARouter | Jetpack Navigation |
|---|---|---|
| 路由方式 | 字符串 Path | Deep Link URI / Safe Args |
| 适用范围 | Activity/Fragment/Service | Fragment 为主 |
| 拦截器 | 内置 | 需自行实现 |
| 类型安全 | 弱(字符串) | 强(Safe Args) |
| 维护状态 | 社区维护 | Google 官方维护 |
新项目推荐 Jetpack Navigation;老项目已使用 ARouter 的无需迁移。
Q2: ARouter 路由表是何时加载的?
答案:
ARouter 在 init() 时需要收集所有 APT 生成的路由表类。默认方式是在运行时扫描 dex 文件中的指定包名下的类,首次较慢。ARouter 提供 Gradle 插件方式,在编译期自动将路由表注册代码注入到 loadRouterMap() 方法中,避免运行时扫描:
build.gradle.kts
plugins {
id("com.alibaba.arouter") // 编译期注册路由表
}