You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android循环依赖场景下如何打开依赖模块的Fragment

跨模块打开Feature模块Fragment的实现方案

核心思路是绕开两个业务模块的直接依赖,通过中间约定完成跨模块实例获取,不会打破现有Gradle依赖规则,以下3种方案可按项目实际情况选择:

  • 方案1:抽离公共约定层(最稳定,推荐中大型项目使用)
    不需要调整现有:feature -> :app的依赖关系,只需要新增一个轻量的公共基础模块(比如命名为:base-common),让:app模块依赖这个公共模块即可(:feature因为已经依赖:app,会自动通过依赖传递获得公共模块的访问能力,不需要额外配置)。

    1. 在公共模块中定义跨模块获取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
        }
    }
    
    1. 在:feature模块中实现上述接口,在应用启动的初始化节点(比如ContentProvider、Application onCreate)把实现类注册到ServiceHub中:
    // feature模块内的实现
    class FeatureEntryProviderImpl : FeatureEntryProvider {
        override fun getTargetFragment(): Fragment = TargetFeatureFragment()
    }
    
    // 初始化时注册
    ServiceHub.registerService(FeatureEntryProvider::class.java, FeatureEntryProviderImpl())
    
    1. 在: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 04:21:40