I am new to Dagger 2 and I am trying to learn it with Kotlin. Let me explain my Project structure first. I am having a Class name "Info":
class Info constructor(var message: String) {}
I have created a module for this class "InfoModule"
@Module
class InfoModule {
@Provides @Choose("HELLO")
fun sayHello(): Info{
return Info(message = "Hello dagger 2")
}
@Provides @Choose("HI")
fun sayHi(): Info{
return Info(message = "Hi dagger 2")
}
}
I have created a component interface for this module named "MagicBox"
@Component(modules = [InfoModule::class])
interface MagicBox {
fun poke(app: MainActivity)
}
Then in the MainActivity I have injected the two fields for "Info"
class MainActivity : AppCompatActivity() {
var textView: TextView? = null;
@Inject @field:Choose("HELLO") lateinit var infoHello: Info
@Inject @field:Choose("HI") lateinit var infoHi: Info
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
DaggerMagicBox.create().poke(this)
textView = findViewById<TextView>(R.id.textView)
textView!!.text = infoHi.message
}
}
@Qualifier
@MustBeDocumented
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
annotation class Choose(val value: String)
As you see above I haved created a @Choose annotation to learn how @Qualifier works. Up to here the code works perfectly and it is really a magic of Dagger :).
PROBLEM STARTS HERE:>> Then I decided to Inject another field called "car" inside my MainActivity in the same way the "info" field is injected in the MainActivity. To do that first i need a Car class.
class Car constructor(var engine: Engine, var wheels: Wheels) {
fun drive(){
Log.d("Car","Driving")
}
}
Now the car class needs Engine and Wheels. So below are Engine and Wheel classes
Engine Class:
class Engine {
}
Wheel Class:
class Wheels {
}
Then I have created a Module for Car class
@Module
class CarModule {
@Provides
fun provideEngine(): Engine{
return Engine()
}
@Provides
fun provideWheel(): Wheels{
return Wheels()
}
@Provides @Choose("NewCar")
fun provideCar(engine: Engine, wheels: Wheels): Car{
Log.d("NewCar", "Created")
return Car(engine, wheels)
}
}
The component for Car is below
@Component (modules = [CarModule::class])
interface CarComponent {
fun injectCar(mainActivity: MainActivity)
}
Then I have injected the car field in the MainActivity and I have tried to called the "drive" method of Car class. Now my MainActivity looks like this.
class MainActivity : AppCompatActivity() {
var textView: TextView? = null;
@Inject @field:Choose("HELLO") lateinit var infoHello: Info
@Inject @field:Choose("HI") lateinit var infoHi: Info
@Inject @field:Choose("NewCar") lateinit var car: Car
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
DaggerMagicBox.create().poke(this)
textView = findViewById<TextView>(R.id.textView)
textView!!.text = infoHi.message
DaggerCarComponent.create().injectCar(this)
car.drive()
}
}
@Qualifier
@MustBeDocumented
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
annotation class Choose(val value: String)
The Logcat Error after MakeProject:
error: [Dagger/MissingBinding] @de.test.testtheapp.Choose("HELLO") de.test.testtheapp.Api.Info cannot be provided without an @Provides-annotated method.
public abstract interface CarComponent {
^
@de.test.testtheapp.Choose("HELLO") de.test.testtheapp.Api.Info is injected at
de.test.testtheapp.MainActivity.infoHello
de.test.testtheapp.MainActivity is injected at
de.test.testtheapp.Components.CarComponent.injectCar(de.test.testtheapp.MainActivity)
What i really find strange is that although the "info" field injection was working prefectly before, why after adding car field injection, the logcat is now showing error about info field injection or Info class. I know its also saying something about "CarComponent". Now nothing is working. Even the "DaggerMagicBox" is unresolved. I am clueless about the error and I am stuck on this since two days. My knowledge about dagger is very limited that I don't know what is the solution. I will be very thankful if some give me a clue. I am using Android Studio 3.5.1 and Dagger version 2.21
You are trying to use CarComponent
to inject dependencies of MainActivity
:
DaggerCarComponent.create().injectCar(this)
But your CarComponent
doesn't have a way to provide Info
:
@Inject @field:Choose("HELLO") lateinit var infoHello: Info
Because the provider method is defined in InfoModule
and CarComponent
doesn't have it in its modules list.
You are using two components to inject the dependencies of MainActivity
:
DaggerMagicBox.create().poke(this)
...
DaggerCarComponent.create().injectCar(this)
You should only use one.
Either add the CarModule
to the list of modules of MagicBox
and remove DaggerCarComponent.create().injectCar(this)
.
Or add the InfoModule
to the list of modules of CarComponent
and remove DaggerMagicBox.create().poke(this)