Dagger 2 Component with differently scoped modules

2019-05-23 09:54发布

问题:

Context

I have two Dagger 2 modules:

  1. NetworkModule, with @Singleton scope, that provides an HTTP client;
  2. ApiModule, with a custom @UserScope scope, that uses the HTTP client to create a consumer for Github's API.

Then, I create a Dagger 2 component, to provide the Retrofit client.

NetworkModule.kt

@Module
class NetworkModule {
    @Provides
    @Singleton
    fun provideHttpClient(): OkHttpClient = OkHttpClient.Builder().build()
}

ApiModule.kt

@Module(includes = [NetworkModule::class])
class ApiModule(private val user: String) {

    @Provides
    @UserScope
    fun provideApi(httpClient: OkHttpClient): GithubApi = Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .client(httpClient)
            .build()
            .create(GithubApi::class.java)
}

ApiComponent.kt

@Component(modules = [ApiModule::class])
@UserScope
interface ApiComponent {
    fun inject(target: GithubRetriever)
}

Issue

When I try to build the application, if I add the @UserScope scope to the ApiComponent then I get the following error message:

e: ApiComponent.java:4: error: ApiComponent scoped with @UserScope may not reference bindings with different scopes:
e: 
e: @dagger.Component(modules = {ApiModule.class})
e: ^
e:       @org.jetbrains.annotations.NotNull @Singleton @Provides okhttp3.OkHttpClient NetworkModule.provideHttpClient()

The same happens if I use @Singleton scope instead of @UserScope.

How should I declare the ApiComponent in order to have a successful build?

回答1:

A single module cannot reference two scopes; which is what is happening when you include the NetworkModule in the ApiModule (@Module(includes = [NetworkModule::class])).

However, a module can depend on a component that uses a different scope.

@Component(modules = [NetworkModule::class])
@Singleton
interface NetworkComponent

@Component(dependencies = [NetworkComponent::class], modules = [ApiModule::class])
interface ApiComponent {
    fun inject(target: GithubRetriever)        
}