question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Can Hilt inject an Abstract class ViewModel?

See original GitHub issue

I am trying to inject abstract class into Fragment etc. in order to inject Fake object without mocking ViewModel with mockito etc. when doing Fragment test.

https://github.com/takahirom/hilt-viewmodel-abstract-inject/blob/master/app/src/main/java/com/github/takahirom/hilt/MainActivity.kt

abstract class MainViewModel : ViewModel() {
    abstract fun onClick()
}

class MainViewModelImpl @ViewModelInject constructor() : MainViewModel() {
    override fun onClick() {
        TODO("Not yet implemented")
    }
}

@InstallIn(ActivityRetainedComponent::class)
@Module
interface Module {
    @Binds
    fun provideMainViewModel(viewModel: MainViewModelImpl): MainViewModel
}

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    val viewModel by viewModels<MainViewModel>()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        println(viewModel)
    }
}

Currently doing this causes a crash.

2020-07-07 19:13:42.284 23496-23496/com.github.takahirom.hilt E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.github.takahirom.hilt, PID: 23496
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.github.takahirom.hilt/com.github.takahirom.hilt.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.github.takahirom.hilt.MainViewModel
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3340)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3484)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2044)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7476)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:939)
     Caused by: java.lang.RuntimeException: Cannot create an instance of class com.github.takahirom.hilt.MainViewModel
        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)
        at androidx.lifecycle.AbstractSavedStateViewModelFactory.create(AbstractSavedStateViewModelFactory.java:69)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:54)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:41)
        at com.github.takahirom.hilt.MainActivity.getViewModel(Unknown Source:2)
        at com.github.takahirom.hilt.MainActivity.onCreate(MainActivity.kt:37)
        at android.app.Activity.performCreate(Activity.java:7989)
        at android.app.Activity.performCreate(Activity.java:7978)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3315)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3484) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2044) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7476) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:939) 
     Caused by: java.lang.InstantiationException: java.lang.Class<com.github.takahirom.hilt.MainViewModel> cannot be instantiated
        at java.lang.Class.newInstance(Native Method)
        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219)
        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) 
        at androidx.lifecycle.AbstractSavedStateViewModelFactory.create(AbstractSavedStateViewModelFactory.java:69) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) 
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:54) 
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:41) 
        at com.github.takahirom.hilt.MainActivity.getViewModel(Unknown Source:2) 
        at com.github.takahirom.hilt.MainActivity.onCreate(MainActivity.kt:37) 
        at android.app.Activity.performCreate(Activity.java:7989) 
        at android.app.Activity.performCreate(Activity.java:7978) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3315) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3484) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2044) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7476)

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:8 (1 by maintainers)

github_iconTop GitHub Comments

8reactions
danysantiagocommented, Jul 8, 2020

This is not easily supported right now, but you can make it work if you change your binds module to:

@InstallIn(ActivityRetainedComponent::class)
@Module
interface Module {
    @Binds
    @IntoMap
    @StringKey("com.github.takahirom.hilt.MainViewModel")
    fun bind(factory: MainViewModelImpl_AssistedFactory): ViewModelAssistedFactory<out ViewModel>
}

while also enabling KAPT corrected error types:

// app's build.gradle
dependencies {
  ...
}

kapt {
  correctErrorTypes = true
}

Hilt ViewModel extension works by declaring modules that bind assisted factories to a map and not by binding concrete ViewModels. Therefore, what you want to do is bind the assisted factory of the concrete ViewModel using the key of the abstract ViewModel so that when HiltViewModelFactory looks up the factory based on class key it uses the assisted factory for the concrete ViewModel. This is suuuper obscure and hence why I mean not ‘easily’ available.

However, if you can expand on the test case your are trying to write that could help us provide some guidance, I’m not sure if you are trying to mock/fake the ViewModel itself for tests, but Hilt testing APIs should allow you to replace dependencies in the ViewModel so you can write a test with the Fragment and the ViewModel.

1reaction
brudaswencommented, Aug 6, 2021

Sorry, my fault. I was playing around too much and requested the concrete VM when it finally worked.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Android Dagger-Hilt How to do Field Injection in abstract class?
I tried providing or binding BaseUseCase class using dagger-hilt such as BaseUseCaseModule.kt, however since it has type parameters, it cannot ...
Read more >
Dependency Injection (Android): Implementation with ...
To provide an instance of Interface or Abstract Class to any dependent object, we can't directly inject any interface or abstract class becuase...
Read more >
Dependency injection with Hilt | Android Developers
Dependency injection. Overview · Manual dependency injection · Dependency injection with Hilt · Hilt in multi-module apps · Use Hilt with other Jetpack ......
Read more >
Understanding Dependency Injection with Hilt. - Nyame Bismark
Hilt is a dependency injection library that reduces a boilerplate code of doing a manual dependency injection in your project. Doing a manual ......
Read more >
The practical guide – Part 4: Dependency injection with Hilt
How Can We Help? · Module – a class in which we provide the dependencies. · Component – an interface or an abstract...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found