Search code examples
androidkotlindagger-2

How to use dependencies from another Module with Dagger2 in Android?


So i Have AppModule and HomeModule. I would like to use in HomeModule the Application context and AppDatabase from AppModule.

I'm getting this error: AppDatabase cannot be provided without an @Provides-annotated method. public abstract interface HomeComponent

@Singleton
@Component(
    modules = [AppModule::class]
)
interface AppComponent {

@Component.Builder
interface Builder {
    fun build(): AppComponent

    @BindsInstance
    fun application(application: Application): Builder
}
}

This is the AppModule:

@Module
class AppModule {

@Provides
@Singleton
fun provideAppDatabase(app: Application): AppDatabase{
    return Room.databaseBuilder(
        context,
        AppDatabase::class.java,
        "app_db"
    )
        .build()
}

}

@Module

How can i use the AppModule dependencies(in this case AppDatabase and the Application) in the HomeModule ?

@Module
class HomeModule {

@Provides
@Singleton
fun provideHomeDao(appDatabase: AppDatabase): HomeDao {
    return appDatabase.homeDao
}

@Provides
@Singleton
fun provideHomeRepository(homeDao: HomeDao): HomeRepository {
    return HomeRepositoryImpl(homeDao)
}
}

The HomeComponent:

@Singleton
@Component(
    modules = [HomeModule::class]
)

interface HomeComponent {
    fun inject(homeFragment: HomeFragment)
}

Solution

  • It will not work because they are unrelated to each other. The solution is:

    The HomeComponent:

    @FragmentScope
    @Subcomponent(
        modules = [HomeModule::class]
    )
    
    interface HomeComponent {
        fun inject(homeFragment: HomeFragment)
    }
    
    @Scope
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    annotation class FragmentScope
    

    Explanation: We should use HomeComponent as subcomponent for AppCompnent and we should use another annotation to avoid conflict.

    The AppComponent:

    @Singleton
    @Component(modules = [AppModule::class])
    interface AppComponent {
    
        fun getHomeFragmentCompnent():HomeComponent
    
        @Component.Builder
        interface Builder {
            fun build(): AppComponent
    
            @BindsInstance
            fun application(application: Application): Builder
        }
    }
    

    Then in your Fragment you can use it like this, for example:

    @FragmentScope
    class AnyFragment:Fragment {
    
        @Inject
        lateinit var dao: HomeDao 
    
        //in onCreateView
        val component = ((application as YourApplcation).applicationComponent)
            .getHomeFragmentCompnent().inject(this)
    }