It is a continuous part of our previous article about Dependency Injection with Hilt. Please check it if you haven't yet.
Let's see some common 'How to' in Hilt in this article.
How to field-inject dependencies in non-Android classes?
As we know, To field-inject a dependency, we use @Inject annotation but it supports only Android classes by default with a predefined entry point @AndroidEntryPoint.
To field-inject a dependency in non-android classes (not supported by @AndroidEntryPoint), we must create a new entry point and access the dependencies through it.
Example
class Developer() {
// We gonna inject for this
private val cup = Cup()
fun drinkCoffee() {
// further steps to drink coffee
}
}
class Cup() {
// A cup
}
As you can see from the example, we gonna field-inject Cup
instance into the Developer
class.
First, define a new entry point which provides the Cup instance.
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@EntryPoint
@InstallIn(SingletonComponent::class)
interface CupEntryPoint {
var cup: Cup
}
Next, access the cup
instance from the entry point in the Developer
class.
import dagger.hilt.android.EntryPointAccessors
class Developer {
// Get the entry point
private val entryPoint = EntryPointAccessors.fromApplication(
applicationContext,
CupEntryPoint::class.java
)
// Get the instance
private val cup = entryPoint.cup
fun drinkCoffee() {
// further steps to drink coffee
}
}
First, get the entry point using the respective method from the EntryPointAccessors.
Here we have used fromApplication()
since the CupEntryPoint was created as a singleton component. You can use other methods like fromActivity()
based on your needs.
After that, we accessed the dependency via the entry point. Simple.
How to provide multiple instances of the same type in Hilt?
In some cases, you may need to inject multiple instances of the same type into a class. In this scenario, you have to differentiate your hilt bindings with Qualifiers.
Example
class Developer @Inject constructor(
private val coffeeCup: Cup,
private val teaCup: Cup
) {
fun drinkCoffee() {
// further steps to drink coffee
coffeeCup.useHere()
}
fun drinkTea() {
// further steps to drink tea
teaCup.useHere()
}
}
class Cup() {
// A cup
}
From the above example, you may guess the requirements. The Developer
class needs two Cup
instances i.e one to drink the coffee and another one to drink the tea.
By default, Hilt doesn't about how to differentiate the bindings when you provide the two instances of the Cup. So we have to use Qualifiers to let the hilt know which one is for coffee and which one is for tea.
@Qualifier
annotation class CoffeeCup
@Qualifier
annotation class TeaCup
@Module
@InstallIn(SingletonComponent::class)
object DeveloperModule {
@Provides
@CoffeeCup
fun provideCoffeeCup(): Cup {
// Your way to create the coffee cup
// For simplicity
return Cup()
}
@Provides
@TeaCup
fun provideTeaCup(): Cup {
// Your way to create the tea cup.
// For simplicity
return Cup()
}
@Provides
fun provideDeveloper(
@CoffeeCup coffeeCup: Cup,
@TeaCup teaCup: Cup
): Developer {
return Developer(coffeeCup, teaCup)
}
}
I have created Two annotation classes - CoffeeCup
and TeaCup
with annotation @Qualifiers.
Then use the qualifiers to differentiate the instances. Simple.
Note: Here I have used the Cup class with no difference and no constructor parameters for the sake of simplicity. Anyway the same way, you can provide bindings as per your needs easily.
I hope you learned something from this article.
Thanks for reading. <3.