【问题标题】:How can Hilt be used effectively in multi-module apps following CLEAN architecture principles?如何在遵循 CLEAN 架构原则的多模块应用程序中有效地使用 Hilt?
【发布时间】:2021-02-16 13:10:20
【问题描述】:

我正在按照清洁架构原则构建 Android 应用。这是我所拥有的:

应用模块

  • 包含所有 Android 依赖项。
  • 将 MVVM 与 Arch 组件中的 ViewModel 结合使用。
  • ViewModel 仅与 UseCases 通信,后者是构造函数注入的。

用例模块

  • 包含所有用例。
  • 用例只与存储库通信,这些存储库是构造函数注入的。

存储库模块

  • 包含所有存储库。
  • 存储库与 Web 服务或数据库等进行通信。
  • 我在这一层定义了一个 Retrofit 接口,存储库接受它的构造函数。

数据模块

  • 包含所有数据模型

我正在尝试在应用程序中使用 Hilt 进行依赖注入。我不想将 Retrofit、OkHttp 等暴露给应用程序模块,因为我不希望开发人员能够将网络代码放入错误的模块中。请记住,app 模块使用 ViewModel,它只能与用例对话。

如何设置?我尝试将 dagger 模块放入每个模块中以定义注入,然后在主 app 模块中包含来自用例的模块:

@Module(includes = [UseCaseModule::class])
@InstallIn(ApplicationComponent::class)
object AppModule

但这不起作用,因为它开始抱怨无法在我想隐藏的其他模块中找到传递依赖项。

【问题讨论】:

  • 你有什么解决办法吗。
  • 我也有同样的问题

标签: android dependency-injection solid-principles clean-architecture dagger-hilt


【解决方案1】:

TLDR:使用 Hilt 2.40+ 版本,它允许使用传递依赖项


自 Hilt 2.37 版以来,有一个 gradle 标志 enableAggregatingTask 允许 Hilt 收集传递依赖项。该标志在 2.40 及更高版本中默认启用。

当您将 gradle 模块设置为 :app -> :usecase -> :repository -> :retrofit (external) 并假设您在 gradle 脚本中使用 implementation 时,您的 Retrofit 实例仍然可以提供并注入到 :repository 模块中,但它不会泄漏到其他模块中模块。

因此,如果您想将 Retrofit 封装在您的存储库模块中,您可以创建

@Module
@InstallIn(SingletonComponent::class)
object RepositoryModule {

  @Provides
  fun provideRetrofit(retrofitBuilder: Retrofit.Builder): YourApi = retrofitBuilder.create<YourApi>()

}

您无需手动将RepositoryModule 包含在:app 中,因为这是由 Hilt 和@InstallIn 注释完成的。

【讨论】:

    【解决方案2】:

    不幸的是,Hilt 目前使用的是整体方法。这意味着您的 app 模块将有权访问您的所有模块。

    我不想将 Retrofit、OkHttp 等暴露给应用模块,因为我不希望开发人员能够将网络代码放入错误的模块中。

    不,您不必在app 模块中包含与网络相关的类。而是在data 模块中。

    但请记住,app 模块仍然可以通过实现 data 模块来间接访问 Retrofit 以使 Hilt 正常工作。 你可以看看这个post

    【讨论】:

    • 那么,如果app 模块不依赖“数据”,Hilt 将无法工作?
    【解决方案3】:

    我有与多模块相同的方法,但比你的更广泛,它可以工作(应用程序、核心、导航、api、数据、域、演示文稿、coreAndroidTest)。

    对于AppModule,您无需指定包含UseCaseModule,只需确保添加@InstallIn ApplicationComponent:

    @Module
    @InstallIn(ApplicationComponent::class)
    class AppModule {
    
        @Provides
        fun provideContext(app: Application): Context = app.applicationContext
    
        @Provides
        fun provideResources(app: Application): Resources = app.resources
    }
    

    在不同的模块中定义 UseCaseModule 时的方式相同:

    @Module
    @InstallIn(ApplicationComponent::class)
    class DomainModule {
    // Your @Provides
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-09
      • 2015-07-25
      • 2021-07-28
      • 1970-01-01
      • 2022-09-25
      • 1970-01-01
      • 2019-08-13
      • 1970-01-01
      相关资源
      最近更新 更多