Search code examples
androiddagger-2androidinjector

Dagger 2 Injector and Binds IntoMap with IntKey


I'm using Dagger 2 Android injector to inject my Activities and Fragments.

I have a generic RecyclerView Adapter and keeping ViewHolderFactories and Binders in a Map.

Here's my adapter:

@Module
class CorePresentationModule {

    @Provides
    fun provideDisplayItemComperator(): DisplayItemComperator = DefaultDisplayItemComperator()

    @Module
    companion object {
        @JvmStatic
        @Provides
        fun provideRecyclerAdapter(
            itemComparator: DisplayItemComperator,
            factoryMap: Map<Int, @JvmSuppressWildcards ViewHolderFactory>,
            binderMap: Map<Int, @JvmSuppressWildcards ViewHolderBinder>,
            androidPreconditions: AndroidPreconditions
        ): RecyclerViewAdapter {
            return RecyclerViewAdapter(
                itemComperator = itemComparator,
                viewHolderFactoryMap = factoryMap,
                viewBinderFactoryMap = binderMap,
                androidPreconditions = androidPreconditions
            )
        }
    }
}

I crate a presentation module for my Fragment like the following:

@Module
abstract class MessagesPresentationModule {

    @Binds
    @IntoMap
    @IntKey(MESSAGE)
    internal abstract fun provideMessagesViewModelFactory(factory: MessagesViewHolder.MessageViewHolderFactory): ViewHolderFactory

    @Binds
    @IntoMap
    @IntKey(MESSAGE)
    internal abstract fun provideMessagesViewHolderBinder(binder: MessagesViewHolder.MessagesViewHolderBinder): ViewHolderBinder

} 

In another fragment i inject my adapter again and create another module for my screen:

@Module
abstract class LinksPresentationModule {

    @Binds
    @IntoMap
    @IntKey(LINK)
    internal abstract fun provideLinksViewModelFactory(factory: LinksViewHolder.LinksViewHolderFactory): ViewHolderFactory

    @Binds
    @IntoMap
    @IntKey(LINK)
    internal abstract fun provideLinksViewHolderBinder(binder: LinksViewHolder.LinksViewHolderBinder): ViewHolderBinder

}

When MESSAGE and LINK is 0 i get a compile error

The same map key is bound more than once for ViewHolderFactory

What's is the best solution to get avoid this execpt putting all IntKeys in a constants class with ordered and incremented?

Thanks.


Solution

  • After long research in my code, I found the missing point. I provide my presentation modules in Application component so it generates only one Map for each type and gets this duplicate MapKey error.

    The same map key is bound more than once for ViewHolderFactory

    I found this useful article in Medium. I realised that created my modules for Application Scope. So SubComponents for my presentation modules does not get generated and Dagger creates only one Map for factory classes. I redesigned my Dagger implementation for my presentation modules to keep them FragmentScoped as it should be like the following code.

    @Module
    abstract class MessagesFragmentModule {
        @FragmentScope
        @ContributesAndroidInjector(modules = [MessagesPresentationModule::class]
        abstract fun contributeMessagesFragment(): MessagesFragment
    }
    
    @Module
    abstract class LinksFragmentModule {
        @FragmentScope
        @ContributesAndroidInjector(modules = [LinksPresentationModule::class]
        abstract fun provideLinksFragment(): LinksFragment
    }
    

    And here's ActivityModule

    @Module
    internal abstract class ActivityModule {
        @ContributesAndroidInjector(
            modules = [MessagesFragmentModule::class,
                LinksFragmentModule::class]
        )
        @ActivityScope
        abstract fun provideMainActivityContributor(): MainActivity
    }