Hilt ViewModel has no zero argument constructor
Asked Answered
E

3

13
Cannot create an instance of class com.comp.app.winners.WinnersViewModel
Caused by: java.lang.InstantiationException: java.lang.Class<com.comp.app.winners.WinnersViewModel> has no zero argument constructor

Getting an error when trying to resolve a viewmodel on a fragment using hilt

// Proj
ext.hilt_version = '2.32-alpha'
ext.lifecycle_version = "2.2.0"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"

// App
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
kapt "com.google.dagger:hilt-compiler:$hilt_version"
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha03'
implementation "androidx.fragment:fragment-ktx:1.1.0"

@HiltAndroidApp
class MyApplication : Application()

@Module
@InstallIn(SingletonComponent::class)
class ApplicationModule {
    @Provides
    fun provideService(): MyService = MyServiceImpl()
}

@AndroidEntryPoint
class HomeActivity : AppCompatActivity() {

    // Fragment is added here
    private fun openFragment(fragment: Fragment) =
        supportFragmentManager.beginTransaction().apply {
            replace(R.id.container, fragment)
            addToBackStack(null)
            commit()
        }
}

@AndroidEntryPoint
class WinnersFragment: Fragment() {
    private val viewModel: WinnersViewModel by viewModels()
}

@HiltViewModel
class WinnersViewModel @Inject constructor(
    private val service: MyService
) : ViewModel()

Is there something else to be done with the fragment? Do i need to provide the viewModel somehow?

NOTE: This is a crash/runtime-error, not a compile error

Equate answered 14/2, 2021 at 15:38 Comment(1)
O
2

You need to upgrade to Fragment 1.2.0 or higher.

As per the Lifecycle 2.2.0 release notes, the new ViewModelProvider APIs that Hilt uses under the hood only apply when using Fragment 1.2.0 or higher. When using an older version of Fragments, those APIs are not connected to fragments and therefore your Hilt enabled ViewModel factory is not used when you use by viewModels().

You should upgrade to Fragment 1.2.5 (the last version of the Fragment 1.2.X set) or to Fragment 1.3.0, both of which contain the necessary API hooks to get Hilt working.

Oxygenate answered 14/2, 2021 at 16:0 Comment(1)
Looks like Hilt is not as safe as it is advertisedEulau
L
19

My issue was nothing to do with my ViewModel, but to do with the fragment it was being applied to.

My ViewModel looks like

@HiltViewModel
class MyViewModel @Inject constructor(repository: MyRepository): ViewModel() {

This is correct, but I still got the exception Caused by: java.lang.InstantiationException: java.lang.Class<com.myapp.MyViewModel> has no zero argument constructor

However, I'd missed the AndroidEntryPoint annotation on the fragment. Adding this back in fixed the problem for me, i.e.

@AndroidEntryPoint
class MyFragment: Fragment() {

    private val viewModel: MyViewModel by viewModels()

    ...
}
Lydia answered 14/6, 2021 at 21:54 Comment(0)
C
7

If getting this error while using compose, it might be because you are using a NavHost and NavHostController. According to official documentation:

If your @HiltViewModel annotated ViewModel is scoped to the navigation graph, use the hiltViewModel composable function that works with fragments or activities that are annotated with @AndroidEntryPoint.

hiltViewModel is part of a dedicated Hilt + Compose Navigation dependency:

dependencies {
    // 1.0.0-beta01 at time of this writing.
    // official docs linked above appear to auto update the version
    implementation("androidx.hilt:hilt-navigation-compose:[version]")
}

Here is a contextualized example of the call to hiltViewModel provided in the same documentation:

// import androidx.hilt.navigation.compose.hiltViewModel

@Composable
fun MyApp() {
    NavHost(navController, startDestination = startRoute) {
        composable("example") { backStackEntry ->
            // Creates a ViewModel from the current BackStackEntry
            // Available in the androidx.hilt:hilt-navigation-compose artifact
            val exampleViewModel = hiltViewModel<ExampleViewModel>()
            ExampleScreen(exampleViewModel)
        }
        /* ... */
    }
}
Cormac answered 4/12, 2021 at 16:14 Comment(0)
O
2

You need to upgrade to Fragment 1.2.0 or higher.

As per the Lifecycle 2.2.0 release notes, the new ViewModelProvider APIs that Hilt uses under the hood only apply when using Fragment 1.2.0 or higher. When using an older version of Fragments, those APIs are not connected to fragments and therefore your Hilt enabled ViewModel factory is not used when you use by viewModels().

You should upgrade to Fragment 1.2.5 (the last version of the Fragment 1.2.X set) or to Fragment 1.3.0, both of which contain the necessary API hooks to get Hilt working.

Oxygenate answered 14/2, 2021 at 16:0 Comment(1)
Looks like Hilt is not as safe as it is advertisedEulau

© 2022 - 2024 — McMap. All rights reserved.