dip*_*dip 7 android dagger dagger-hilt
我尝试将 App 迁移到Dagger Hilt。在我的旧设置中,我为调试版本中的调试版本或不同的产品风格切换了一个模块。例如:
@Module
open class NetworkModule {
@Provides
@Singleton
open fun provideHttpClient(): OkHttpClient {
...
}
}
class DebugNetworkModule : NetworkModule() {
override fun provideHttpClient(): OkHttpClient {
...
}
}
Run Code Online (Sandbox Code Playgroud)
然后我在调试版本中交换了正确的模块:
val appComponent = DaggerAppComponent.builder().networkModule(DebugNetworkModule())
Run Code Online (Sandbox Code Playgroud)
由于 Hilt 管理着ApplicationComponent我看不到交换模块的可能性。
但是,当我查看生成的源代码(对我来说DaggerApp_HiltComponents_ApplicationC:)时,我看到 Hilt 确实为不同的模块生成了一个构建器(在 旁边未使用ApplicationContextModule)。
我知道这不是最佳做法。NetworkModule为每个构建类型/产品风格提供不同的s会更干净。但这会导致大量重复的代码。
在测试中,我可以卸载模块并安装测试模块。但这在生产代码中似乎是不可能的。
还有其他方法可以实现我的目标吗?
Hilt 的关键在于,默认情况下,源代码中的模块 = 应用程序中安装的模块。
理想情况下,您将为不同的构建提供替代模块,并通过sourceSets 区分使用哪些模块
在发布源集中:
@InstallIn(ApplicationComponent::class)
@Module
object ReleaseModule {
@Provides
fun provideHttpClient(): OkHttpClient { /* Provide some OkHttpClient */ }
}
Run Code Online (Sandbox Code Playgroud)
在调试源集中:
@InstallIn(ApplicationComponent::class)
@Module
object DebugModule {
@Provides
fun provideHttpClient(): OkHttpClient { /* Provide a different OkHttpClient */ }
}
Run Code Online (Sandbox Code Playgroud)
@BindsOptionalOf如果选项 1 不可行,因为您想覆盖源中仍然存在的模块,则可以使用 dagger可选绑定
@InstallIn(ApplicationComponent::class)
@Module
object Module {
@Provides
fun provideHttpClient(
@DebugHttpClient debugOverride: Optional<OkHttpClient>
): OkHttpClient {
return if (debugOverride.isPresent()) {
debugOverride.get()
} else {
...
}
}
}
@Qualifier annotation class DebugHttpClient
@InstallIn(ApplicationComponent::class)
@Module
abstract class DebugHttpClientModule {
@BindsOptionalOf
@DebugHttpClient
abstract fun bindOptionalDebugClient(): OkHttpClient
}
Run Code Online (Sandbox Code Playgroud)
然后仅在调试配置中的文件中:
@InstallIn(ApplicationComponent::class)
@Module
object DebugHttpClientModule {
@Provides
@DebugHttpClient
fun provideHttpClient(): OkHttpClient { ... }
}
Run Code Online (Sandbox Code Playgroud)
@IntoMap如果您需要更多的粒度,而不仅仅是实现 + 测试/调试覆盖,您可以使用多重绑定和映射,使用键作为要选择的实现的优先级。
@InstallIn(ApplicationComponent::class)
@Module
object Module {
@Provides
fun provideHttpClient(
availableClients: Map<Int, @JvmSuppressWildcards OkHttpClient>
): OkHttpClient {
// Choose the available client from the options provided.
val bestEntry = availableClients.maxBy { it.key }
return checkNotNull(bestEntry?.value) { "No OkHttpClients were provided" }
}
}
Run Code Online (Sandbox Code Playgroud)
主要应用模块:
@InstallIn(ApplicationComponent::class)
@Module
object MainModule {
@Provides
@IntoMap
@IntKey(0)
fun provideDefaultHttpClient(): OkHttpClient {
...
}
}
Run Code Online (Sandbox Code Playgroud)
调试覆盖:
@InstallIn(ApplicationComponent::class)
@Module
object DebugModule {
@Provides
@IntoMap
@IntKey(1)
fun provideDebugHttpClient(): OkHttpClient {
...
}
}
Run Code Online (Sandbox Code Playgroud)
如果您使用选项 3,我要么将提供的类型设为可空/可选,要么避免使用,@Multibinds以便在没有绑定到映射中的情况下在编译时而不是运行时失败
| 归档时间: |
|
| 查看次数: |
1373 次 |
| 最近记录: |