I'm facing some issues trying to use Dagger with multiple Components, I have the following (each class is in its own file):
Scopes:
@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class PrototypeScope
Modules:
@Module(includes = [RepositoriesModule::class])
class GetRandomBookUseCaseModule {
@Provides
@Singleton
fun provideGetRandomBookUseCase(booksRepository: BooksRepository) =
GetRandomBookUseCase(booksRepository)
}
@Module
class RepositoriesModule {
@Provides
@Singleton
fun providesBooksRepository(): BooksRepository = BooksRepositoryImpl()
@Provides
@Singleton
fun providesPreferencesRepository(): PreferencesRepository = PreferencesRepositoryImpl()
}
@Module
class BookReaderModule(val ctx: Context) {
@Provides
@PrototypeScope
fun provideBookReader(getRandomBookUseCase: GetRandomBookUseCase) =
BookReader(ctx, getRandomBookUseCase)
}
Components:
@Component(
modules = [GetRandomBookUseCaseModule::class]
)
interface UseCasesComponent {
}
@Component(
dependencies = [UseCasesComponent::class],
modules = [BookReaderModule::class]
)
@PrototypeScope
interface BookReaderFragmentComponent {
fun inject(bookReaderFragment: BookReaderFragment)
}
Then, in BookReaderFragment I have the following:
class BookReaderFragment : Fragment() {
@Inject lateinit var bookReader: BookReader
val component: BookReaderFragmentComponent by lazy {
DaggerBookReaderFragmentComponent
.builder()
.useCasesComponent(DaggerUseCasesComponent.create())
.bookReaderModule(BookReaderModule(context!!))
.build()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
component.inject(this)
...
}
...
}
However, Dagger is failing ought to:
error: GetRandomBookUseCase cannot be provided without an @Inject constructor or an @Provides-annotated method.
What is going on? Why Dagger is not finding the provided method?
Thanks a lot
UPDATE: Adding RepositoriesModule as included in GetRandomBookUseCaseModule. After this change, I have realised that, although the error message, the issue is related with the way the BookReader is injected. If I remove the @Injected from the BookReaderFragment this way:
class BookReaderFragment : Fragment() {
lateinit var bookReader: BookReader
val component: BookReaderFragmentComponent by lazy {
DaggerBookReaderFragmentComponent
.builder()
.useCasesComponent(DaggerUseCasesComponent.create())
.bookReaderModule(BookReaderModule(context!!))
.build()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
component.inject(this)
...
}
...
}
Then there's no error, however it will not work on runtime, but when the @Inject is set, then the error is thrown.
Include RepositoriesModule
into GetRandomBookUseCaseModule
@Module(includes = {RepositoriesModule.class})
class {
@Provides
@Singleton
fun provideGetRandomBookUseCase(booksRepository: BooksRepository) =
GetRandomBookUseCase(booksRepository)
}
And Component should be
@Component(
modules = [GetRandomBookUseCaseModule::class]
)
interface UseCasesComponent {
GetRandomBookUseCase getRandomBookUseCase();
}