Android, Hilt: Inject multiple instances of a Object to the Dependent Modules.
Android, ViewModel, Dependency Injection, Annotation, Dagger2/Hilt, MVVM, JetPack
If get to know something new by reading my articles, don't forget to endorse me on LinkedIn
Topic
In our Modern Application Development, we use DI (Dagger/Dagger2/ Hilt). As we follow Depdendency Injection, we love to inject (@Inject
) objects as much as possible instead of creating/destroying the objects at our own.
Specially, we might need to inject multiple instances of same type objects to the dependent module.
So, How do we resolve this scenarios by following Dependency Injection?
Simple, by using Annotations.
What or How @Named
Annotation works?
@Named
to differentiate between different objects of the same type bound in the same scope.
@Provides
@Named("userId")
fun provideUserId(): Int = DataHolder.userId
@Provides
@Named("profileId")
fun provideProfileId(): Int = DataHolder.profileId
Without the @Named
qualifier, the injector would not know which Int
to bind to which variable.
If you want to create annotations that act like
@Named
, use the@Qualifier
annotation when creating them.If you look at
@Named
, it is itself annotated with@Qualifier
.
Let's get into the coding part
object DataHolder {
@Volatile
var userId: Int = -1
@Volatile
var profileId: Int = -1
}
We are using In-Memory holder to transfer data from one module to another module. @Volatile
mark the objects to be stored in the Main Memory to access the updated instances by multiple Clients or Threads.
We will inject the stored objects instances to the Dependent Modules by using DI.
@Module
@InstallIn(ViewModelComponent::class)
object ViewModelComponent {
@Provides
@Named("userId")
fun provideUserId(): Int = DataHolder.userId
@Provides
@Named("profileId")
fun provideProfileId(): Int = DataHolder.profileId
}
Create a new Object
called ViewModelComponent
and mark the Object
as @Module
(That contributes to the object graph) and @InstallIn(ViewModelComponent::class)
(That declares which component(s) the annotated class should be included in when Hilt generates the components.)
Here, we are providing the multiple values of Int Object as User ID and Profile ID to the dependent module by annotating the Functions/APIs
with @Provided
and @Named
@HiltViewModel
class ExampleViewModel @Inject constructor(
@Named("userId") private val userId: Int,
@Named("profileId") private val profileId: Int
) :
ViewModel() {
init {
println("$userId, $profileId provided by Hilt")
}
}
Here, the client/dependent module ExampleViewModel
received the multiple instances of Int Object by Injecting (@Inject
) the constructor and Annotating parameters with respective unique IDs (userId
, profileId
).
class TestFragment : Fragment() {
companion object {
fun newInstance(userId: Int, profileId: Int): TestFragment {
/*Store the user id to the *DataHolder**/
DataHolder.userId = userId
DataHolder.profileId = profileId
return TestFragment()
}
}
}
Finally, before creating a new instance of Fragment
or Activity
store the values to the DataHolder
to provide the new values to the dependent modules by using Hilt.
Full Implementation in Kotlin
Happy Coding...