Hilt not detecting dependencies despite #Provides and #Inject - kotlin

I am practicing clean architecture in an app, so for this I divided the application in modules, App, data, domain. I have created the modules of the dependencies on the data module, where I have created the UseCasesModule. Such Module has been provided with the #Module tag and #Installin(SingletonComponent::class), so on the App module I have added as a module dependency the Domain and Data modules. But when I am trying to inject the UseCase on the ViewModel I get the following error
`
com.example.usecases.GetUserByPersonaNameUseCase cannot be provided without an #Inject constructor or an #Provides-annotated method.
com.example.usecases.GetUserByPersonaNameUseCase is injected at
com.example.dota2stats.di.FactoryModule.providesHomeViewModelFactory(getUserByPersonaNameUseCase)`
This is not my first time with Hilt, so I know that I have to add the #Provides on the method that will provide the dependency, but right now is not working, I have restarted the app plenty of times. How can I solve this? Here my code
Here is the dependency
#Module
#InstallIn(SingletonComponent::class)
class UseCasesModule {
#Singleton
#Provides
fun providesGetUserByPersonaNameUseCase(repository: Repository): GetUserByPersonaNameUseCase {
return GetUserByPersonaNameUseCase(repository)
}
}
Here the ViewModel where I am trying to inject it
class HomeViewModel (private val getUserByPersonaNameUseCase: GetUserByPersonaNameUseCase) : BaseViewModel() {
override fun handleAction(action: Action): Flow<State> {
TODO("Not yet implemented")
}
}
I have tried by adding the #Inject constructor tag like this but still no results
class HomeViewModel #Inject constructor(private val getUserByPersonaNameUseCase: GetUserByPersonaNameUseCase) : BaseViewModel() {
override fun handleAction(action: Action): Flow<State> {
TODO("Not yet implemented")
}
}
Here the ViewModelFactory
class HomeViewModelFactory #Inject constructor(private val getUserByPersonaNameUseCase: GetUserByPersonaNameUseCase) :
ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return HomeViewModel(getUserByPersonaNameUseCase) as T
}
}
And here is how I am trying to use it
#AndroidEntryPoint
class MainActivity : AppCompatActivity() {
#Inject
lateinit var homeViewModelFactory: HomeViewModelFactory
private lateinit var homeViewModel: HomeViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
homeViewModel = ViewModelProvider(this, homeViewModelFactory)[HomeViewModel::class.java]
}
}

Did you try to annotate the ViewModel with #HiltViewModel?
#HiltViewModel
class HomeViewModel #Inject constructor(private val getUserByPersonaNameUseCase: GetUserByPersonaNameUseCase) : BaseViewModel() {
override fun handleAction(action: Action): Flow<State> {
TODO("Not yet implemented")
}
}

Related

error: [Dagger/MissingBinding] core.domain.usecase.NotePreferencesUseCase cannot be provided without an #Provides-annotated method

I am trying to create sharedpreferences using Hilt. Already take a look for some search but I get this error.
error: [Dagger/MissingBinding] core.domain.usecase.NotePreferencesUseCase cannot be provided without an #Provides-annotated method.
Here's my code
NotePreferenceRepository
#Singleton
class NotePreferencesRepository #Inject constructor(
private val sharedPreferences: SharedPreferences
): INotePreferencesRepository {
private val edit = sharedPreferences.edit()
override fun setTheme(theme: String) {
edit.putString(THEME, theme)
}
override fun getTheme(): String? {
return sharedPreferences.getString(THEME, "")
}
companion object {
private val THEME = "theme"
}
}
NotePreferencesModule
#Module
#InstallIn(SingletonComponent::class)
object NotePreferencesModule {
#Provides
#Singleton
fun provideNotePreferences(#ApplicationContext context: Context): SharedPreferences {
return context.getSharedPreferences("note_prefs", Context.MODE_PRIVATE)
}
}
Repository Module
#Module
#InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
#Binds
abstract fun providePreferencesRepository(notePreferencesRepository: NotePreferencesRepository): INotePreferencesRepository
}
INotePreferencesRepository
interface INotePreferencesRepository {
fun setTheme(theme: String)
fun getTheme(): String?
}
NotePreferencesInteractor
class NotePreferencesInteractor #Inject constructor(private val notePreferencesRepository: INotePreferencesRepository): NotePreferencesUseCase {
override fun setTheme(theme: String) {
notePreferencesRepository.setTheme(theme)
}
override fun getTheme(): String? = notePreferencesRepository.getTheme()
}
NotePreferencesUseCase
interface NotePreferencesUseCase {
fun setTheme(theme: String)
fun getTheme(): String?
}
SettingViewModel
#HiltViewModel
class SettingViewModel #Inject constructor(private val notePreferencesUseCase: NotePreferencesUseCase): ViewModel() {
fun getTheme() = notePreferencesUseCase.getTheme()
fun setTheme(theme: String) {
notePreferencesUseCase.setTheme(theme)
}
}
SOLVED
forgor to add AppModule
#Module
#InstallIn(ViewModelComponent::class)
abstract class AppModule {
#Binds
#ViewModelScoped
abstract fun provideNotePreferencesUseCase(notePreferencesInteractor: NotePreferencesInteractor): NotePreferencesUseCase
}
So view model can use usecase

Can't provide dependency from subcomponent

I'm new in Dagger2 and learn it in test project. I want to provide SuperObject from subcomponent with custom scope but got error: [Dagger/MissingBinding] ru.rsb.daggerproject.objects.SuperObject cannot be provided without an #Inject constructor or an #Provides-annotated method. I aleready indicated method provides SuperObject with #Provides annotation. Please explain me my mistakes.
I have such graph:
#Singleton
#Component(modules = [AndroidInjectionModule::class, ModuleA::class, ModuleB::class, ActivityModule::class])
interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
fun inject(app: App)
}
#Module(subcomponents = [Subcomponent::class])
class ModuleB {
#Singleton
#Provides
fun provideDepB(): DepB {
return DepB(Random.nextInt())
}
#Singleton
#Provides
fun provideObjectWithDepB(value: DepB): ObjectWithDepB {
return ObjectWithDepB.newInstance(value)
}
}
#Subcomponent(modules = [SubcomponentModule::class])
#CustomScope
interface Subcomponent {
#Subcomponent.Builder
interface Builder {
fun subcomponentModule(subModule: SubcomponentModule): Builder
fun build(): ru.rsb.daggerproject.Subcomponent
}
}
#Module
class SubcomponentModule {
#CustomScope
#Provides
fun provideSuperObject(value: ObjectWithDepB): SuperObject = SuperObject.newInstance(value)
}

cannot be provided without an #Inject constructor or an #Provides-annotated method

This my App Component class
#Singleton
#Component(dependencies = {}, modules = {AppModule.class,RoomModule.class, NetworkModule.class})
public interface AppComponent {
void inject(CSATApplication applicationController);
void inject(AverageScoreActivity averageScoreActivity);
CsatDao csaatdao();
CSATDatabase csatDatabase();
RemoteRepositoryImpl getRemoteRepo();
LocalRepositoryImpl getLocalRepo();
Application application();
BaseUrlHolder provideBaseUrlHolder();
Retrofit getRetrofit();
CompositeDisposable getCompositeDisposable();
CompositeDisposable getVMCompositeDisposable();
}
#Module
public class RoomModule {
private CSATDatabase CSATDatabase;
public RoomModule(Application mApplication) {
CSATDatabase = Room.databaseBuilder(mApplication, CSATDatabase.class, AppConstants.DATABASE_NAME).build();
}
#Singleton
#Provides
CSATDatabase providesRoomDatabase() {
return CSATDatabase;
}
#Singleton
#Provides
CsatDao providesCsatDao(CSATDatabase CSATDatabase) {
return CSATDatabase.getCsatDao();
}
#Singleton
#Provides
public RemoteRepository getRemoteRepo(NetworkService networkService){
return new RemoteRepositoryImpl(networkService);
}
#Singleton
#Provides
public LocalRepository getLocalRepo(CsatDao csatDao, Executor exec){
return new LocalRepositoryImpl(csatDao, exec);
}
#Provides
#Named("activity")
public CompositeDisposable getCompositeDisposable(){
return new CompositeDisposable();
}
#Provides
#Named("vm")
public CompositeDisposable getVMCompositeDisposable(){
return new CompositeDisposable();
}
Injecting in activity
#Inject #field:Named("activity")
lateinit var compositeDisposable: CompositeDisposable
#Inject
lateinit var averageViewModelFactory: AverageViewModelFactory
#Inject
lateinit var averageViewModel: AverageViewModel
Injecting In View Model Factory
class AverageViewModelFactory #Inject
constructor() : #JvmSuppressWildcards ViewModelProvider.Factory {
#Inject
lateinit var localRepository: LocalRepository
#Inject
lateinit var remoteRepository: RemoteRepository
#Inject #field:Named("vm")
lateinit var compositeDisposable: CompositeDisposable
#Override
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(AverageViewModel::class.java)) {
return AverageViewModel(localRepository, remoteRepository, compositeDisposable) as T
}
throw IllegalArgumentException("Wrong ViewModel class")
}
}
class AverageViewModel #Inject constructor(
val localRepository: LocalRepository,
val remoteRepository: RemoteRepository,
val compositeDisposable: CompositeDisposable
) : BaseViewModel<AverageInteractor.view>(){
Gradel
//Dependencies injection
implementation 'com.google.dagger:dagger:2.19'
implementation 'com.google.dagger:dagger-android:2.19'
kapt 'com.google.dagger:dagger-compiler:2.19'
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
kapt 'com.google.dagger:dagger-android-processor:2.19'
compileOnly 'javax.annotation:jsr250-api:1.0'
Error
error: [Dagger/MissingBinding] io.reactivex.disposables.CompositeDisposable cannot be provided without an #Inject constructor or an #Provides-annotated method.
public interface AppComponent {
^
io.reactivex.disposables.CompositeDisposable is provided at
com.sisindia.csat.deps.AppComponent.getCompositeDisposable()
It is also requested at:
com.sisindia.csat.projectmodules.score.AverageViewModel(…, compositeDisposable)
The following other entry points also depend on it:
com.sisindia.csat.deps.AppComponent.inject(com.sisindia.csat.projectmodules.score.AverageScoreActivity)
com.sisindia.csat.deps.AppComponent.getVMCompositeDisposable()
You need to annotate your CompositeDisposable's with #Named in AppComponent and AverageViewModel classes, like this:
public interface AppComponent {
...
#Named("activity") CompositeDisposable getCompositeDisposable();
#Named("vm") CompositeDisposable getVMCompositeDisposable();
}
class AverageViewModel #Inject constructor(
...
#Named("vm") val compositeDisposable: CompositeDisposable
) : BaseViewModel<AverageInteractor.view>(){

Dagger 2 #Provides can't be apply to static function in Kotlin?

I have the following Java code which works fine
#Module(subcomponents = {MainActivityComponent.class})
abstract public class ActivityBuilder {
#Provides
#Singleton
static Context provideContext(Application application) {
return application;
}
#Binds
#IntoMap
#ClassKey(MainActivity.class)
abstract AndroidInjector.Factory<?> bindMainActivity(MainActivityComponent.Builder builder);
}
When I convert it to Kotlin
#Module(subcomponents = [MainActivityComponent::class])
abstract class ActivityBuilder {
companion object {
#Provides
#Singleton
fun provideContext(application: Application): Context {
return application
}
}
#Binds
#IntoMap
#ClassKey(MainActivity::class)
abstract fun bindMainActivity(builder: MainActivityComponent.Builder): AndroidInjector.Factory<*>
}
I got error stating I can't have my #Provides on the static function.
error: #Provides methods can only be present within a #Module or #ProducerModule
public final android.content.Context provideContext(#org.jetbrains.annotations.NotNull()
^
How could I fix that?
Apparently the below works.
#Module(subcomponents = [MainActivityComponent::class])
abstract class ActivityBuilder {
#Module
companion object {
#JvmStatic
#Provides
#Singleton
fun provideContext(application: Application): Context {
return application
}
}
#Binds
#IntoMap
#ClassKey(MainActivity::class)
abstract fun bindMainActivity(builder: MainActivityComponent.Builder): AndroidInjector.Factory<*>
}

error: expecting member declaration and error: unresolved reference: in kotlin

In class Parent.
interface Humenable{
fun Run()
}
In class Child.
fun main(args:Array<String>)
{
class Student : Humenable{
Overrides fun Run(){
println("Pass")
}
}
}
Try something like this:
interface Humenable {
fun Run()
}
class Student : Humenable {
override fun Run() {
println("Pass")
}
}
fun main(args: Array<String>) {
val student = Student()
student.Run()
}
Your mistakes:
You used Overrides instead override modifier (simple typo).
You made Student class declaration in fun {} scope.