1. TheRouter入门:为什么你需要它
如果你正在开发一个大型的Android应用,尤其是采用模块化架构的项目,组件间的通信和页面跳转一定会让你头疼。各个模块之间如何优雅地互相调用?页面跳转如何避免硬编码?参数传递怎样才能更安全?这些问题TheRouter都能帮你解决。
我第一次接触TheRouter是在一个电商App的重构项目中。当时我们的代码已经膨胀到难以维护,首页Activity里塞满了各种跳转逻辑,参数传递全靠Bundle,经常出现类型不匹配的崩溃。更糟糕的是,由于业务模块互相依赖,一个小小的改动就可能引发连锁反应。TheRouter的出现彻底改变了这种局面。
简单来说,TheRouter是一个功能强大的Android路由框架,它能帮你:
- 解耦模块依赖:各个业务模块不再需要直接引用彼此
- 统一导航管理:所有页面跳转通过路由表集中管理
- 安全参数传递:类型安全的参数传递机制
- 灵活拦截控制:可以在路由过程中加入各种业务逻辑检查
2. 基础配置:5分钟快速上手
2.1 添加依赖
首先在模块的build.gradle中添加依赖。我建议使用KSP替代KAPT,因为它的处理速度更快:
implementation 'cn.therouter:router-runtime:1.1.4' ksp 'cn.therouter:apt:1.1.4'如果你还在使用KAPT,也可以这样配置:
kapt 'cn.therouter:apt:1.1.4'这里有个小技巧:在项目的gradle.properties中加入以下配置可以显著提升注解处理速度:
org.gradle.parallel=true org.gradle.caching=true kapt.incremental.apt=true2.2 初始化配置
在Application中初始化TheRouter。我通常会在这里添加一些调试配置:
class MyApp : Application() { override fun onCreate() { super.onCreate() TheRouter.init(this) { setDebugMode(BuildConfig.DEBUG) setCheckRouteMap(true) // 开启路由表校验 setLogger { tag, msg -> // 自定义日志输出 if(BuildConfig.DEBUG) Log.d(tag, msg) } } } }注意:如果你使用了MultiDex,记得在ProGuard规则中添加以下配置:
-keep class cn.therouter.** { *; } -keep class * implements cn.therouter.IRouteMap { *; }3. 路由声明与导航
3.1 页面路由声明
声明页面路由非常简单,使用@Route注解即可。我习惯在Activity的companion object中定义路由路径:
@Route(path = "app://product/detail") class ProductDetailActivity : AppCompatActivity() { companion object { const val KEY_PRODUCT_ID = "product_id" const val KEY_FROM_PAGE = "from_page" } // ... }最佳实践:
- 路由路径建议采用"模块名/页面功能"的格式
- 所有参数key定义为常量,避免硬编码
- 复杂的参数建议封装为Parcelable对象传递
3.2 基本导航操作
最简单的导航方式:
TheRouter.build("app://product/detail").navigation()带参数的导航:
TheRouter.build("app://product/detail") .withInt(ProductDetailActivity.KEY_PRODUCT_ID, 12345) .withString(ProductDetailActivity.KEY_FROM_PAGE, "home") .navigation()实用技巧:如果你需要知道导航是否成功,可以这样处理:
TheRouter.build("app://product/detail") .navigation { success, exception -> if (!success) { Toast.makeText(context, "页面打开失败", Toast.LENGTH_SHORT).show() exception?.printStackTrace() } }4. 高级路由功能
4.1 路由拦截器实战
拦截器是TheRouter最强大的功能之一。比如实现登录检查:
object LoginInterceptor : RouteInterceptor { override fun intercept(chain: Chain) { if (UserManager.isLogin()) { chain.proceed() } else { TheRouter.build("app://login") .withString("target_path", chain.path()) .navigation() chain.onInterrupt() } } } // 使用方式 TheRouter.build("app://user/center") .addInterceptor(LoginInterceptor) .navigation()进阶用法:你可以为拦截器设置优先级,数字越小优先级越高:
@Interceptor(priority = 100) // 高优先级 class AuthInterceptor : RouteInterceptor { // ... }4.2 服务发现与依赖注入
TheRouter的服务发现功能可以完美解决模块间服务调用的问题。首先定义服务接口:
interface IUserService { fun getUserInfo(): User fun updateUserInfo(user: User) }然后在实现类上添加@Service注解:
@Service(impl = UserServiceImpl::class) class UserServiceImpl : IUserService { // 实现方法... }使用时通过TheRouter获取服务实例:
val userService = TheRouter.getService(IUserService::class.java) userService?.getUserInfo()注意:服务实现类可以放在任意模块中,调用方只需要知道接口定义即可。
5. 项目实战技巧
5.1 多模块路由管理
在大型项目中,我建议每个业务模块维护自己的路由表。创建一个Routes类集中管理:
object ProductRoutes { const val PRODUCT_LIST = "app://product/list" const val PRODUCT_DETAIL = "app://product/detail" const val PRODUCT_SEARCH = "app://product/search" fun navigateToDetail(context: Context, productId: Int) { TheRouter.build(PRODUCT_DETAIL) .withInt("id", productId) .navigation(context) } }5.2 参数处理最佳实践
在目标页面中获取参数时,建议封装一个专门的解析方法:
@Route(path = ProductRoutes.PRODUCT_DETAIL) class ProductDetailActivity : AppCompatActivity() { private val productId by lazy { TheRouter.getParamInt("id", 0) } private val fromPage by lazy { TheRouter.getParamString("from", "") } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (!checkParams()) { finish() return } // ... } private fun checkParams(): Boolean { if (productId <= 0) { Toast.makeText(this, "无效的商品ID", Toast.LENGTH_SHORT).show() return false } return true } }5.3 FlowTask初始化管理
TheRouter的FlowTask功能可以优雅地解决模块初始化顺序问题。比如我们需要在应用启动时初始化用户模块和统计模块:
@FlowTask( taskName = "init_user", dependsOn = ["init_network"], // 依赖网络模块初始化 runInThread = TaskThread.MAIN // 在主线程执行 ) fun initUser(context: Context) { UserManager.init(context) }然后在Application中触发初始化:
TheRouter.init(this) { // ... setFlowTaskExecutor { taskName, runnable -> // 可以自定义执行策略 runnable.run() } } TheRouter.executeFlowTask()6. 调试与问题排查
6.1 路由表检查
在调试阶段,可以通过以下命令查看完整路由表:
TheRouter.debug()这会输出所有注册的路由和服务信息。如果发现某个路由没有生效,首先检查这里是否包含该路由。
6.2 常见问题解决
问题1:路由跳转失败,返回success=false
- 检查路径是否正确
- 确认目标Activity已添加@Route注解
- 检查是否被拦截器拦截
问题2:参数获取为null或默认值
- 确认参数key完全匹配
- 检查参数类型是否正确
- 如果是自定义对象,确保实现了Parcelable
问题3:KSP/KAPT处理失败
- 清理build目录后重新构建
- 检查注解处理器版本是否匹配
- 确认模块的kapt/ksp配置正确
在实际项目中,TheRouter帮我们减少了80%以上的模块间耦合代码,页面跳转逻辑变得更加清晰可维护。特别是在大型团队协作中,每个模块只需要关心自己暴露的路由和服务接口,而不需要了解其他模块的实现细节。