Dagger Hilt: cannot be provided without an @Provides-annotated method
Asked Answered
T

4

11

When I use interface like below in viewmodel

class MainViewModel @ViewModelInject constructor(
    private val trafficImagesRepository: TrafficImageRepository, <----------------- Not working
    @Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() 

I am getting an error like below

cannot be provided without an @Provides-annotated method.
  public abstract static class SingletonC implements MainApplication_GeneratedInjector,

My interface is like below

interface TrafficImageRepository {
    suspend fun getTrafficImages() : NetworkResponse<TrafficData, ErrorTrafficImages>
}

And Repository class is like below

class DefaultTrafficImagesRepository @Inject constructor(private val trafficImageService: TrafficImageService) : TrafficImageRepository {

    override suspend fun getTrafficImages(): NetworkResponse<TrafficData, ErrorTrafficImages> {
        lateinit var response: NetworkResponse<TrafficData, ErrorTrafficImages>
        withContext(IO) {
            val currentTimestamp = Constants.getCurrentTime()
            response = trafficImageService.getTrafficImages(currentTimestamp)
        }
        return response
    }
}

But when I use DefaultTrafficImagesRepository class directly instead of Interface my app is able to build without any error.

class MainViewModel @ViewModelInject constructor(
    private val trafficImagesRepository: DefaultTrafficImagesRepository , <----------------- Working Fine
    @Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel()
Taunt answered 30/1, 2021 at 8:38 Comment(0)
P
13

You must to bind interface

@Module
@InstallIn(ViewModelComponent::class)
abstract class RepositoryModule {

    @Binds
    abstract fun bindRepository(impl: DefaultTrafficImagesRepository): TrafficImageRepository 
}

and use viewmodel inject in this way

@HiltViewModel
class MainViewModel @Inject constructor(
    private val trafficImagesRepository: TrafficImageRepository,
    @Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() 
Phyle answered 30/1, 2021 at 9:8 Comment(4)
For Test Cases I have used FakeTrafficImageRepository so should I also need to bind it as well?Taunt
@PanchalAmit you can use "UninstallModules" in your test and pass new one you want it.Phyle
It worked! I changed from ActivityComponent to SingletonComponent, why it didn't work with ActivityComponent?Musclebound
@DouglasFornaro cause lifecycle of activityPhyle
C
0

Better late than never. Besides you need do the thing mentioned in the accepted answer.If you are working with compose or the latest Hilt version, init your ViewModel by the way of: val viewModel: YourViewModel by viewModels() do not use the way of: @Inject lateinit var viewModel: YourViewModel

Chops answered 30/10, 2022 at 4:54 Comment(1)
what is wrong with first aproach ?Playtime
Y
0

Just to add to this post in case anyone needs it in the future, it's important to, as Jun Du mentioned, to init your ViewModel as val viewModel: YourViewModel by viewModels() or val viewModel by viewModels<YourViewModel>() because the method viewModels creates, under the hood, the factory that your viewModel needs to receive the injected dependencies in your constructor. For that, you need the Android KTX extension as exemplified in this Android Hilt doc

Yb answered 18/7, 2023 at 17:0 Comment(0)
E
0

I had same problem in my multi-module project, because there wasn't added dependency on gradle-module with target hilt-module to main app-module (what contains every hilt-modules). Also, sometimes I've forgot to add kapt to the module dependencies %)

Eec answered 7/5, 2024 at 4:14 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.