Dagger-Hilt: @ViewModelInject is not injecting MyViewModel and crash?

13,404

Solution 1

Apparently I miss out adding a kapt, which is kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'

The list of dependencies in my build.gradle is as below

    implementation 'androidx.fragment:fragment-ktx:1.2.5'
    implementation "androidx.lifecycle:lifecycle-viewmodel:2.2.0"
    implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
    implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01"
    implementation 'com.google.dagger:hilt-android:2.28-alpha'
    kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
    kapt 'com.google.dagger:hilt-android-compiler:2.28-alpha'

Just for completeness, the plugin is below

apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'kotlin-kapt'

Solution 2

@ViewModelInject is deprecated in the newer hilt version

https://developer.android.com/reference/androidx/hilt/lifecycle/ViewModelInject

Use HiltViewModel

@HiltViewModel
class TasksViewModel @Inject constructor(
    val taskRepository: TaskRepository
) : ViewModel() {

}

Solution 3

I'd like to add that If you are on a multi-module project, you have to have kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01' on the :app module as well for it to work.

Solution 4

Try to search for your ViewModel's generated java files like below via Find in Path (⇧⌘F or Ctrl+Shift+F).
enter image description here
If there are no auto-generated java files. It means you forgot to add this dependency to your module's gradle file which generates necessary java files for every @HiltViewModel annotation.

kapt "androidx.hilt:hilt-compiler:$version"

Share:
13,404
Elye
Author by

Elye

Android Design, Development and Deployment

Updated on June 06, 2022

Comments

  • Elye
    Elye about 2 years

    In exploring the ViewModelInject of Dagger-Hilt, I follow the example in https://developer.android.com/training/dependency-injection/hilt-jetpack#viewmodels

    I try to inject the ViewModel into my activity as follow

    import android.app.Application
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import androidx.activity.viewModels
    import androidx.hilt.Assisted
    import androidx.hilt.lifecycle.ViewModelInject
    import androidx.lifecycle.*
    import androidx.savedstate.SavedStateRegistryOwner
    import dagger.hilt.android.AndroidEntryPoint
    import dagger.hilt.android.HiltAndroidApp
    import kotlinx.android.synthetic.main.activity_main.*
    import javax.inject.Inject
    import javax.inject.Singleton
    
    @HiltAndroidApp
    class MainApplication: Application()
    
    @AndroidEntryPoint
    class MainActivity : AppCompatActivity() {
    
        private val viewModel: MyViewModel by viewModels()
    
        private val textDataObserver =
            Observer<String> { data -> text_view.text = data }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            viewModel.showTextDataNotifier.observe(this, textDataObserver)
            btn_fetch.setOnClickListener { viewModel.fetchValue() }
        }
    }
    
    class MyViewModel @ViewModelInject constructor(
        @Assisted val savedStateHandle: SavedStateHandle,
        val repository: Repository
    ) :
        ViewModel(), LifecycleObserver {
    
        private val showTextLiveData
                = savedStateHandle.getLiveData<String>("DefaultKey")
    
        val showTextDataNotifier: LiveData<String>
            get() = showTextLiveData
    
        fun fetchValue() {
            showTextLiveData.value = repository.getMessage()
        }
    }
    
    
    @Singleton
    class Repository @Inject constructor() {
        fun getMessage() = "From Repository"
    }
    
    

    It crash complaining

         Caused by: java.lang.RuntimeException: Cannot create an instance of class com.elyeproj.simplehilt.MyViewModel
            at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221)
            at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:278)
            at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106)
            at androidx.hilt.lifecycle.HiltViewModelFactory.create(HiltViewModelFactory.java:69)
    

    I try manually creating the ViewModel using the view model factory (the non-injection approach), it works fine.

    import android.app.Application
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import androidx.activity.viewModels
    import androidx.hilt.Assisted
    import androidx.hilt.lifecycle.ViewModelInject
    import androidx.lifecycle.*
    import androidx.savedstate.SavedStateRegistryOwner
    import dagger.hilt.android.AndroidEntryPoint
    import dagger.hilt.android.HiltAndroidApp
    import kotlinx.android.synthetic.main.activity_main.*
    import javax.inject.Inject
    import javax.inject.Singleton
    
    @HiltAndroidApp
    class MainApplication: Application()
    
    @AndroidEntryPoint
    class MainActivity : AppCompatActivity() {
    
        private val viewModel: MyViewModel by viewModels{
            MyViewModelFactory(this, Repository(), intent.extras)
        }
    
        private val textDataObserver =
            Observer<String> { data -> text_view.text = data }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            viewModel.showTextDataNotifier.observe(this, textDataObserver)
            btn_fetch.setOnClickListener { viewModel.fetchValue() }
        }
    }
    
    class MyViewModelFactory(
        owner: SavedStateRegistryOwner,
        private val repository: Repository,
        defaultArgs: Bundle? = null
    ) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
        override fun <T : ViewModel> create(key: String, modelClass: Class<T>, handle: SavedStateHandle
        ): T {
            return MyViewModel(
                handle,
                repository
            ) as T
        }
    }
    
    class MyViewModel @ViewModelInject constructor(
        @Assisted val savedStateHandle: SavedStateHandle,
        val repository: Repository
    ) :
        ViewModel(), LifecycleObserver {
    
        private val showTextLiveData
                = savedStateHandle.getLiveData<String>("DefaultKey")
    
        val showTextDataNotifier: LiveData<String>
            get() = showTextLiveData
    
        fun fetchValue() {
            showTextLiveData.value = repository.getMessage()
        }
    }
    
    @Singleton
    class Repository @Inject constructor() {
        fun getMessage() = "From Repository"
    }
    

    Did I do anything wrong in the use of @ViewModelInject?

  • Sharad
    Sharad almost 4 years
    My Problem was, I was using viewmodel in Fragment and on Fragment i didn't mention @AndroidEntryPoint. I mentioned that on Activity but not on Fragment.
  • Devarshi
    Devarshi almost 4 years
    You saved my day! I was missing implementation for "androidx.lifecycle:lifecycle-viewmodel:2.2.0"
  • A. Cedano
    A. Cedano almost 4 years
    I haved the same error. In my case, I was missing implementation "androidx.lifecycle:lifecycle-viewmodel:2.2.0" and implementation "androidx.lifecycle:lifecycle-extensions:2.2.0". When I added that into app/build.gradle the problem was solved.
  • Andrew Chelix
    Andrew Chelix over 3 years
    I tried using this while doing the Android Testing course but I'm still getting this error: InstantiationException: java.lang.Class<com.example.android.architecture.blueprints.‌​todoapp.tasks.TasksV‌​iewModel> has no zero argument constructor
  • Abdul Mateen
    Abdul Mateen about 3 years
    If anyone like @AndrewChelix getting an issue even after adding the above answer then makes sure all hilt dependencies should be updated also.
  • Sagar Kacha
    Sagar Kacha almost 3 years
    This saved my day!. Thanks!
  • Kirguduck
    Kirguduck over 2 years
    ...and {Remove the old androidx.hilt:hilt-lifecycle-viewmodel dependency from your build.gradle file} from here - github.com/google/dagger/releases/tag/dagger-2.34