Can Hilt inject an Abstract class ViewModel?
See original GitHub issueI 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.
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:
- Created 3 years ago
- Comments:8 (1 by maintainers)
Top 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 >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
This is not easily supported right now, but you can make it work if you change your binds module to:
while also enabling KAPT corrected error types:
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.
Sorry, my fault. I was playing around too much and requested the concrete VM when it finally worked.