跳到主要内容

路由框架

问题

什么是路由框架?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) {}
}

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 如何选择?

答案

维度ARouterJetpack Navigation
路由方式字符串 PathDeep Link URI / Safe Args
适用范围Activity/Fragment/ServiceFragment 为主
拦截器内置需自行实现
类型安全弱(字符串)强(Safe Args)
维护状态社区维护Google 官方维护

新项目推荐 Jetpack Navigation;老项目已使用 ARouter 的无需迁移。

Q2: ARouter 路由表是何时加载的?

答案

ARouter 在 init() 时需要收集所有 APT 生成的路由表类。默认方式是在运行时扫描 dex 文件中的指定包名下的类,首次较慢。ARouter 提供 Gradle 插件方式,在编译期自动将路由表注册代码注入到 loadRouterMap() 方法中,避免运行时扫描:

build.gradle.kts
plugins {
id("com.alibaba.arouter") // 编译期注册路由表
}

相关链接