16

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?

Elye
  • 53,639
  • 54
  • 212
  • 474
  • Does this answer your question? [Cannot create instance of viewmodel after using Hilt in Android](https://stackoverflow.com/questions/62471849/cannot-create-instance-of-viewmodel-after-using-hilt-in-android) – EraftYps Jun 30 '20 at 14:07

8 Answers8

50

@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() {

}
Linh
  • 57,942
  • 23
  • 262
  • 279
  • 2
    I tried using this while doing the Android Testing course but I'm still getting this error: InstantiationException: java.lang.Class has no zero argument constructor – Andrew Chelix Mar 22 '21 at 18:14
  • 1
    If anyone like @AndrewChelix getting an issue even after adding the above answer then makes sure all hilt dependencies should be updated also. – Abdul Mateen May 05 '21 at 07:33
  • ...and {Remove the old androidx.hilt:hilt-lifecycle-viewmodel dependency from your build.gradle file} from here - https://github.com/google/dagger/releases/tag/dagger-2.34 – Kirguduck Mar 06 '22 at 17:14
32

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'
Elye
  • 53,639
  • 54
  • 212
  • 474
  • 5
    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. – Sharad Aug 06 '20 at 06:22
  • 2
    You saved my day! I was missing implementation for "androidx.lifecycle:lifecycle-viewmodel:2.2.0" – Devarshi Aug 18 '20 at 17:54
  • 1
    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. – A. Cedano Sep 23 '20 at 03:38
12

For Jetpack Compose lovers if hiltViewModel() is not being resolved, just ensure you have these 3 dependencies:

implementation "com.google.dagger:hilt-android:2.42"
kapt "com.google.dagger:hilt-android-compiler:2.42"
implementation 'androidx.hilt:hilt-navigation-compose:1.0.0'

Of course, remember to apply the plugins.

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id "kotlin-kapt"
    id "dagger.hilt.android.plugin"
}
Tonnie
  • 4,865
  • 3
  • 34
  • 50
2

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.

Jim
  • 1,027
  • 1
  • 10
  • 19
1

For me all the dependencies were perfectly placed but missed out on inheriting the ViewModel class (androidx.lifecycle.ViewModel)

ViewModel()

class MainViewModel @ViewModelInject constructor(): ViewModel() 
MDT
  • 1,535
  • 3
  • 16
  • 29
1

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"

Yekta Sarıoğlu
  • 1,435
  • 2
  • 12
  • 20
0

Make sure the following dependencies are in your app/build.gradle:

    // ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0"
    implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"

    // Hilt
    implementation 'com.google.dagger:hilt-android:2.33-beta'
    kapt 'com.google.dagger:hilt-compiler:2.33-beta'

    // Hilt ViewModel
    implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"
    kapt "androidx.hilt:hilt-compiler:1.0.0-beta01"
Andrew Chelix
  • 1,012
  • 11
  • 16
0

You should add

implementation 'androidx.fragment:fragment-ktx:1.5.7'

into your build.gradle file

Serhii Hrabas
  • 401
  • 1
  • 5
  • 12