4

Assisted Injection in ViewModel using Hilt

 1 year ago
source link: https://www.simplifiedcoding.net/assisted-injection-in-viewmodel/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Assisted Injection in ViewModel using Hilt

November 4, 2022 by Belal Khan

You are using hilt for dependency injection in your android project. You may encounter a situation where you need to provide some dynamic dependencies to your ViewModel. In this situation you can use Assisted Injection in ViewModel. For the example I will take the project that we created in the last tutorial.

You can check the last ktor android client tutorial to get the source code of the project, as that project is required for this tutorial.

Need for Assisted Injection

Once you have got the project from the last tutorial, open it in android studio and go to MainViewModel.kt .

You will see the following code in this file.

@HiltViewModel
class MainViewModel @Inject constructor(
    private val repository: MoviesRepository
) : ViewModel() {
    private val _movies = MutableStateFlow<Resource<List<Movie>>?>(null)
    val movies: StateFlow<Resource<List<Movie>>?> = _movies
    init {
        viewModelScope.launch {
            _movies.value = Resource.Loading
            _movies.value = repository.getPopularMovies()

The above ViewModel is annotated with @HiltViewModel , and @Inject constructor ; this means for this ViewModel, hilt will provide the required parameters. In this case we have only one parameter that is our repository.

Now assume a situation where we need to provide one more parameter movieId: Int .  This time movieId  needs to be dynamic, as for every movie the movieId  will change. In this case hilt cannot provide the movieId. Now for this situation we have two parameters for our MainViewModel .

  1. private val repository: MoviesRepository  : Hilt will provide this instance.
  2. private val movieId: Int  : This is a dynamic value, that we want to provide manually.

For situation like this, we can use Assisted Injection in ViewModel.

Now let’s understand how to perform an Assisted Injection in this ViewModel.

Assisted Injection in ViewModel

Modify the ViewModel like this.

class MainViewModel @AssistedInject constructor(
    private val repository: MoviesRepository,
    @Assisted
    private val movieId: Int,
) : ViewModel() {
    private val _movies = MutableStateFlow<Resource<List<Movie>>?>(null)
    val movies: StateFlow<Resource<List<Movie>>?> = _movies
    init {
        viewModelScope.launch {
            _movies.value = Resource.Loading
            _movies.value = repository.getPopularMovies()
    @AssistedFactory
    interface Factory {
        fun create(movieId: Int) : MainViewModel
    companion object {
        fun provideMainViewModelFactory(factory: Factory, movieId: Int) : ViewModelProvider.Factory {
            return object: ViewModelProvider.Factory {
                override fun <T : ViewModel> create(modelClass: Class<T>): T {
                    return factory.create(movieId) as T

In the above code you can see many changes. Let’s try to understand the changes one by one.

  • @AssistedInject constructor(... : Whenever you have some parameters that needs to be injected manually (or dynamically) you need to use this annotation instead of the normal @Inject  annotation for the constructor. Also note that we have removed the @HiltViewModel  annotation. As this time we are going to use a factory to build the ViewModel instance.
  • @Assisted private val movieId: Int  : Now for all the parameters that needs to be passed dynamically we will use @Assisted  annotation.
    @AssistedFactory
    interface Factory {
        fun create(movieId: Int) : MainViewModel
  • A factory interface is needed, that we will mark with @AssistedFactory  annotation, inside this interface we need a function that will take all the dynamic parameters required. In this case we have only one parameter. This function will return the actual ViewModel.
    companion object {
        fun provideMainViewModelFactory(factory: Factory, movieId: Int) : ViewModelProvider.Factory {
            return object: ViewModelProvider.Factory {
                override fun <T : ViewModel> create(modelClass: Class<T>): T {
                    return factory.create(movieId) as T
  • Inside the companion object we have a function that is returning ViewModelProvider.Factory . Inside this factory we have the overriden function create()  and this function is creating the ViewModel using the factory that we passed as a parameter; we also passed movieId .
  • Now we can inject the AssistedFactory in our Activity/Fragment, and then we can call the provideMainViewModelFactory()  function to get the factory that will create the ViewModel instance. Sounds confusing? Let’s see how to do it.

Creating ViewModel with Assisted Injection

Now let’s come to the MainActivity and here we will initialize the MainViewModel.  We can use the following code to create the ViewModel.

    @Inject lateinit var factory: MainViewModel.Factory
    private val viewModel: MainViewModel by viewModels {
        MainViewModel.provideMainViewModelFactory(factory, 1)

Pretty simple right? We can use the @Inject  to inject the @AssistedFactory  inside our Activity/Fragment, but we cannot do it inside a composable function.

To get the factory inside a composable, we need to create an EntryPoint.

Creating an EntryPoint

We will create one more interface named ViewModelFactoryProvider .

@EntryPoint
@InstallIn(ActivityComponent::class)
interface ViewModelFactoryProvider {
    fun mainViewModelFactory(): MainViewModel.Factory

The function inside this interface will return the AssistedFactory that we defined inside the ViewModel. Now we can use this function to get the factory inside a composable. And with the help of this factory we can create the ViewModel.

val factory = EntryPointAccessors.fromActivity(
  LocalContext.current as Activity,
  ViewModelFactoryProvider::class.java
).mainViewModelFactory()
val viewModel: MainViewModel = viewModel(factory = MainViewModel.provideMainViewModelFactory(factory, 1))

And this is how we can create the viewModel instance inside a composable function.

I hope you found this tutorial helpful and learned something. If you have any confusion regarding Assisted Injection in ViewModel then please leave your comments below. You can also watch the video to understand Assisted Injection in ViewModel in more detail.

Please share this post with your friends, if you think it is helpful. Thank You 🙂

Hi, my name is Belal Khan and I am a Google Developers Expert (GDE) for Android. The passion of teaching made me create this blog. If you are an Android Developer, or you are learning about Android Development, then I can help you a lot with Simplified Coding.

Checkout these tutorials as well:

  • Android ViewModel Unit Test Tutorial
  • Android Hilt Tutorial - Injecting Dependencies with Hilt
  • QR Code Reader Android Kotlin Tutorial using ML Kit
  • Firebase Authentication using MVVM with Hilt and Coroutines
  • Kotlin Coroutines Tutorial for Android - Start using Coroutines in Your App
  • Android Jetpack Paging 3.0 Tutorial - Paged RecyclerView using Retrofit

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK