In Dagger, it provides another way to inject/provide resources by using constructor injection.
The typical case is that we use constructor injection
in a class to inject needed resources as class parameters. In this way, we can directly use the required resources without declaring the @Inject
keyword. Another pro tip is that it has very high potentialities to let your injection more robust and more flexible. Let’s see how we can use constructor injection for providing multi-source injection for the different release versions.
First of all, please check my repo. Let’s see the data models in the project at the beginning; I’ve done many changes for these data models.
Data Model Changes
For a car resource, it’s probably a petrol engine or an electric engine. We can create an engine interface; it’s just a simple interface with a method - getEngineName() to let the driver know which engine the car uses.
1 | interface Engine { |
As I mentioned before, we could have several different engines for this car.
PetrolEngine
1 | class PetrolEngine constructor(): Engine { |
ElectricEngine
1 | class ElectricEngine constructor(): Engine { |
Both of these engines could have their properties, and I use the constructor injector for these two classes, which means these two car engines can provide themselves as resources. The constructor injection is much easier than creating a module to provide the resource. A class that uses this way would be automatically
injected into a component.
In this case, if we directly use these two classes, it would work. But we need to assign one of these engines in our project explicitly. It has a more flexible way to do. Let’s see.
ElectricEngineModule
1 |
|
PetrolEngineModule
1 |
|
I create two modules for these two different engines, respectively. But I don’t use @Provides,
instead, I use @Binds.
If you don’t understand what’s difference between @Provides
& @Binds,
I would suggest you should know these two keywords first. The differences are not only on performance but also for a dynamic linking here.
Both modules have a function called engine
and return an Engine
type. That shows a possibility: we can get two different engines via a feature flag. Let’s see how to do that.
ElectricEngineComponent
1 |
|
PetrolEngineComponent
1 |
|
I create two components for these two modules separately. You might notice those two components all extended from the EngineComponent. Then what’s the EngineComponent
?
EngineComponent
1 | interface EngineComponent { |
It’s just a primary interface with a function engine().
What’s this purpose for this interface? Don’t worry, and we would use it into our ApplicationComponent as a dependency. Let’s take a look.
1 |
|
You might wonder: can we treat this EngineComponent
as a dependency in a real Dagger component? Yes, Dagger allows us to do this. And you can see, I also create a builder for this EngineComponent. Ok, even though we can do this, what does it mean? Let’s go back to see the Mercedes
class in the project. This class implements the Car interface and accepts an injection - Engine. That means for each different Mercedes Benz car, and it might either use a petrol engine or an electric engine that depends on what model it is.
Mercedes
1 | class Mercedes constructor( |
The magic part is: we don’t need to give this Mercedes Benz car a specific engine setting. Instead, we can ignore that and wait for an engine injection.
Then, how to inject an engine into this car?
AppInjector
1 | val applicationComponent = DaggerApplicationComponent.builder() |
I injected a petrol engine into a component that means this car should have a petrol engine. Let’s see.
Dagger Petrol Engine
What about an electric engine?
AppInjector
1 | val applicationComponent = DaggerApplicationComponent.builder() |
Dagger Electric Engine
What about a particular version engine?
1 | # in AppInjector |
Dagger Special Version Engine
You can see how flexible it is. In this way, we basically can create whatever engine we want and provide this engine to a car in a natural way.
Happy coding, enjoy.