Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HiltViewModel: Cannot create an instance of class

I am using Hilt. After updating to 1.0.0-alpha03 I got warnings that @ViewModelInject is deprecated and I should use @HiltViewModel. But when I change it I got an error:

java.lang.RuntimeException: Cannot create an instance of class com.example.LoginViewModel
...
Caused by: java.lang.NoSuchMethodException: com.example.LoginViewModel.<init> [class android.app.Application]

Previous my ViewModel looked like this:

class LoginViewModel @ViewModelInject constructor(
    application: Application,
    private val repository: RealtimeDatabaseRepository
) : AndroidViewModel(application)

Now it looks like this:

@HiltViewModel
class LoginViewModel @Inject constructor(
    application: Application,
    private val repository: RealtimeDatabaseRepository
) : AndroidViewModel(application)

Fragment where ViewModel is injected:

@AndroidEntryPoint
class LoginFragment : Fragment(R.layout.fragment_login)
{
    private val viewModel: LoginViewModel by activityViewModels()
}

Injected class:

@Singleton
class RealtimeDatabaseRepository @Inject constructor() { }

When I deleted private val repository: RealtimeDatabaseRepository from ViewModel constructor it is working


I was using hilt version 2.30.1-alpha when I updated to 2.31.2-alpha, as USMAN osman suggested, the error is gone.

like image 842
iknow Avatar asked Feb 04 '21 11:02

iknow


2 Answers

With new hilt version lots of stuff has been changed.
You also have to upgrade your hilt android, hilt compiler and hilt gradle plugin to:2.31-alpha
I made mock sample exactly the way you did i had same issue, after going through hilt's docs i found new way to inject dependencies to viewModels, you have to make separate module for dependencies which are going to inject in the viewModel with special component called ViewModelComponent:

@Module
@InstallIn(ViewModelComponent::class) // this is new
object RepositoryModule{

    @Provides
    @ViewModelScoped // this is new
    fun providesRepo(): ReposiotryIMPL { // this is just fake repository
        return ReposiotryIMPL()
    }

}

here is what docs says about ViewModelComponent and ViewModelScoped

All Hilt View Models are provided by the ViewModelComponent which follows the same lifecycle as a ViewModel, i.e. it survives configuration changes. To scope a dependency to a ViewModel use the @ViewModelScoped annotation.

A @ViewModelScoped type will make it so that a single instance of the scoped type is provided across all dependencies injected into the Hilt View Model.
link: https://dagger.dev/hilt/view-model.html

then your viewModel:

@HiltViewModel
class RepoViewModel @Inject constructor(
    application: Application,
    private val reposiotryIMPL: ReposiotryIMPL
) : AndroidViewModel(application) {}

UPDATE
It is not mandatory that you should be using ViewModelComponent or ViewModelScoped as i did in the above example. You can also use other scopes or components depends on your usecase.
Furthermore read docs, i put the dagger-hilt's link above.

like image 119
USMAN osman Avatar answered Sep 28 '22 07:09

USMAN osman


I've seen this happens when the Fragment/Activity that is using the ViewModel is missing the @AndroidEntryPoint annotation, for instance:

import androidx.fragment.app.viewModels

@AndroidEntryPoint
class SampleFragment: BaseFragment() {
     val viewModel: SampleFragmentViewModel by viewModels()
}

If the annotation is not present, the exact same error you describe will happen.

like image 33
Chepech Avatar answered Sep 28 '22 05:09

Chepech