Search code examples
androidkotlindependency-injectionkodein

org.kodein.di.Kodein$NotFoundException: 2 bindings found that match bind()


I have an interface WordsDataSource using which I have implemented two concrete classes namely WordsLocalDataSource that deals with local database and another WordsRemoteDataSource that deals with manipulating data online on the server. The problem is when I try to inject the two classes in repository class using abstract class name WordsDataSource like

DefaultWordsRepository(
     private val wordsRemoteDataSource: WordsDataSource,
     private val wordsLocalDataSource: WordsDataSource) {

And adding dependencies in Application class like

class WordsApplication : Application(), KodeinAware {

    override val kodein = Kodein.lazy {
        import(androidXModule(this@WordsApplication))
        bind() from singleton { WordsDatabase.getInstance(instance()) }
        bind<WordsDao>() with singleton { instance<WordsDatabase>().wordsDao() }
        bind() from singleton { WordsLocalDataSource(instance()) }
        bind() from singleton { WordsRemoteDataSource() }
        bind<WordsRepository>() with singleton { DefaultWordsRepository(instance(), instance()) }
        bind() from provider { ViewModelFactory(instance()) }
    }

Then upon running the app I encounter the following issue in the logcat

org.kodein.di.Kodein$NotFoundException: 2 bindings found that match bind<WordsDataSource>() with ?<WordsFragment>().? { ? }:
        bind<WordsLocalDataSource>() with singleton { WordsLocalDataSource }
        bind<WordsRemoteDataSource>() with singleton { WordsRemoteDataSource }

I have tried the workaround for this by simply declaring the variables by their respective concrete class names like

DefaultWordsRepository(
     private val wordsRemoteDataSource: WordsRemoteDataSource,
     private val wordsLocalDataSource: WordsLocalDataSource) {

But still want to know whether or not is there any way to resolve the issue.

I am using the following dependencies for kodein

implementation "org.kodein.di:kodein-di-generic-jvm:6.3.3"
implementation "org.kodein.di:kodein-di-framework-android-x:6.3.3"

Solution

  • You have done it the right way by writing the explicit types:

    DefaultWordsRepository(
         private val wordsRemoteDataSource: WordsRemoteDataSource,
         private val wordsLocalDataSource: WordsLocalDataSource)
    

    When working with sub-types we cannot know what kind of implementation to choose. Writing

    DefaultWordsRepository(
         private val wordsRemoteDataSource: WordsDataSource,
         private val wordsLocalDataSource: WordsDataSource)
    

    Doesn't cannot find if you want both sub-types or twice the WordsRemoteDataSource or WordsLocalDataSource. Thus, you need to explicit define your types. Even, we could put WordsRemoteDataSource in the property wordsLocalDataSource, as we cannot rely on variable names.