Android循环依赖场景下如何打开依赖模块的Fragment
核心思路是绕开两个业务模块的直接依赖,通过中间约定完成跨模块实例获取,不会打破现有Gradle依赖规则,以下3种方案可按项目实际情况选择:
方案1:抽离公共约定层(最稳定,推荐中大型项目使用)
不需要调整现有:feature -> :app的依赖关系,只需要新增一个轻量的公共基础模块(比如命名为:base-common),让:app模块依赖这个公共模块即可(:feature因为已经依赖:app,会自动通过依赖传递获得公共模块的访问能力,不需要额外配置)。- 在公共模块中定义跨模块获取Fragment的抽象接口,以及对应的服务存取工具类:
// 公共模块中的接口 interface FeatureEntryProvider { fun getTargetFragment(): Fragment } // 公共模块中的服务管理工具 object ServiceHub { private val serviceMap = mutableMapOf<Class<*>, Any>() fun <T> registerService(clazz: Class<T>, impl: T) { serviceMap[clazz] = impl as Any } @Suppress("UNCHECKED_CAST") fun <T> getService(clazz: Class<T>): T? { return serviceMap[clazz] as? T } }- 在
:feature模块中实现上述接口,在应用启动的初始化节点(比如ContentProvider、Application onCreate)把实现类注册到ServiceHub中:
// feature模块内的实现 class FeatureEntryProviderImpl : FeatureEntryProvider { override fun getTargetFragment(): Fragment = TargetFeatureFragment() } // 初始化时注册 ServiceHub.registerService(FeatureEntryProvider::class.java, FeatureEntryProviderImpl())- 在
:app模块需要打开该Fragment的位置,直接从ServiceHub获取对应服务,拿到Fragment实例即可完成跳转,全程不需要引用:feature模块的任何类:
// app侧调用 val fragment = ServiceHub.getService(FeatureEntryProvider::class.java)?.getTargetFragment() fragment?.let { supportFragmentManager.beginTransaction() .replace(R.id.container, it) .commit() }方案2:路由框架实现(适合已接入路由组件的项目)
如果项目已经接入ARouter、TheRouter等成熟路由组件,不需要额外写抽象接口,直接给目标Fragment加路由注解即可:// feature模块内的Fragment加注解 @Route(path = "/feature/page/target") class TargetFeatureFragment : Fragment() { // 原有业务逻辑 }在
:app侧直接通过路由路径构建Fragment实例,路由框架会自动完成跨模块的类加载、实例创建和参数注入,不需要模块间产生直接依赖:// app侧获取实例 val fragment = ARouter.getInstance().build("/feature/page/target").navigation() as Fragment // 后续执行常规Fragment跳转逻辑即可方案3:反射直接加载(适合小型项目快速实现)
如果项目体量小,不想新增模块也不想引入路由依赖,可以直接通过Fragment的全类名反射创建实例,成本最低:fun buildFeatureFragment(): Fragment? { return runCatching { val fragmentClazz = Class.forName("你的feature模块TargetFeatureFragment的完整全类名") fragmentClazz.newInstance() as Fragment }.getOrNull() }注意这种方式属于硬编码类路径,后续如果feature侧修改了Fragment的包名、类名,编译期不会提示错误,运行时会出现类找不到的崩溃,仅适合小规模项目快速迭代使用。
补充提示:当前
:feature依赖:app的依赖关系本身不符合常规组件化分层规范,正常架构下app模块仅作为壳工程承担打包、整合职责,业务feature模块应该依赖公共层而非主app模块,后续如果要推进组件化拆分建议逐步调整依赖关系,降低跨模块调用的维护成本。
内容的提问来源于stack exchange,提问作者Mahbub Munna

