Android, Hilt: Inject multiple instances of a Object to the Dependent Modules.

Android, ViewModel, Dependency Injection, Annotation, Dagger2/Hilt, MVVM, JetPack

ยท

3 min read

Android, Hilt: Inject multiple instances of a Object to the Dependent Modules.

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...

ย