Dagger 2: @Component.Builder is missing setters for required modules or components: [appi.example.com.dagger.AppModule]`
Remove the below code from the AppModule.class and rebuild the project
@Provides
@Singleton
Application provideContext(SomeApplication application) {
return application;
}
I think this provides a somewhat clearer explanation on the use of @BindsInstance
and removal of @Provides Application
, Dagger 2 Component Builder:
@BindsInstance
What?Here’s the definition :
Marks a method on a component builder or subcomponent builder that allows an instance to be bound to some type within the component. — source
WHAAT? I don’t understand it either
Here’s a simple hint of when to use it :
@BindsInstance methods should be preferred to writing a @Module with constructor arguments and immediately providing those values. — source
I come from Spring Boot and Dagger 2 is OMG so much more complicated. :(
So based on my extremely limited experience with Dagger 2, this happens because there a *Module
with a constructor argument which is improperly configured. I still don't know how to properly configure the Module with a constructor argument, but I rather follow recommended approach given by Dagger 2 documentation, and that is to remove the constructor argument(s) and use @BindsInstance
and @Inject
instead.
e.g.
@Module
class NetModule { // no constructor argument here!
@Inject @Named("mqttServer") // replaced by @Inject
internal lateinit var mqttServer: String
}
and in AppComponent
:
@Singleton
@Component(modules = [AndroidSupportInjectionModule::class, AppModule::class, NetModule::class, ActivityBuilder::class])
interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: Application): Builder
@BindsInstance // you'll call this when setting up Dagger
fun mqttServer(@Named("mqttServer") mqttServer: String): Builder
fun build(): AppComponent
}
fun inject(app: GeoAssistantApp)
}
Then you provide the dependencies of the modules when constructing the DaggerAppComponent
from the Application
subclass (make sure you specify the subclass name in AndroidManifest.xml
):
class GeoAssistantApp : Application(), HasActivityInjector, HasSupportFragmentInjector {
@Inject
internal lateinit var activityDispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
@Inject
internal lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>
override fun onCreate() {
super.onCreate()
Log.i(GeoAssistantApp::class.java.simpleName, "Initializing DaggerAppComponent...")
DaggerAppComponent.builder()
// list of modules/dependencies of modules that are part of this component need to be created here too
.application(this)
.mqttServer(getString(R.string.mqtt_server))
.build()
.inject(this)
}
override fun activityInjector(): AndroidInjector<Activity> {
return activityDispatchingAndroidInjector
}
override fun supportFragmentInjector(): AndroidInjector<Fragment> {
return fragmentDispatchingAndroidInjector
}
}
Note that the support-v4
Fragment
vs native Fragment
usage can be a source of problems. e.g. for support-v4, you need to use AndroidSupportInjectionModule
, HasSupportFragmentInjector
, while with native, you need to use AndroidInjectionModule
, HasFragmentInjector
.
In my case I was using an object Module, so I had to annotate provider method with @JvmStatic
@Module
object GsonModule {
@JvmStatic
@Singleton
@Provides
fun provideGson() = Gson()
}