Reputation: 773
I have 3 repositories:
interface MainRepository {
...
}
interface LocalRepository {
...
}
interface WebRepository {
...
}
Each Repository has it's own implementation:
@Singleton
class MainRepositoryImpl @Inject constructor(
private val localRepository: LocalRepository,
private val webRepository: WebRepository
) : MainRepository {
...
}
@Singleton
class LocalRepositoryImpl @Inject constructor(
private val localMapper: LocalMapper
private val popularMovieDao: PopularMovieDao
) : LocalRepository {
...
}
@Singleton
class WebRepositoryImpl @Inject constructor(
private val webMapper: WebMapper,
private val popularMovieApi: PopularMovieApi
) : WebRepository {
...
}
As you can see, MainRepository
needs to have both other repositories injected into it, however,I can't really figure out how to do it.
Of course I can inject it with type of LocalRepositoryImpl
or WebRepositoryImpl
but I want to inject it with type of LocalRepository
or WebRepository
for more generalized approach.
Here is the module that I tried writing:
@InstallIn(ApplicationComponent::class)
@Module
object Module {
@Singleton
@Provides
fun provideWebRepository(): WebRepository {
return WebRepositoryImpl(mapper = WebMapper(), popularMovieApi = PopularMovieApi.getInstance())
}
@Singleton
@Provides
fun provideLocalRepository(): LocalRepository {
return LocalRepositoryImpl(mapper = LocalMapper(), // Here I can't really
// figure out how to get @Dao since it requires DB
// which requires context and etc
// which makes me think that I've got completely wrong approach to this)
}
}
My Module of LocalData:
@InstallIn(ApplicationComponent::class)
@Module
object LocalDataSourceModule {
@Singleton
@Provides
fun provideMainDatabase(@ApplicationContext context: Context): MainDatabase = MainDatabase.getInstance(context)
@Provides
fun providePopularMovieDao(mainDatabase: MainDatabase): PopularMovieDao = mainDatabase.popularMovieDao()
}
My Module of WebData:
@InstallIn(ApplicationComponent::class)
@Module
object RemoteDataSourceModule {
@Singleton
@Provides
fun providePopularMovieApi(): PopularMovieApi = PopularMovieApi.getInstance()
}
How do I properly Inject Implementations that I have (LocalRepositoryImpl
& WebRepositoryImpl
) while maintaining types of interfaces(LocalRepository
& `WebRepository)??
Upvotes: 0
Views: 1613
Reputation: 9732
Use @Binds
. Instead of your object Module
use following module:
@InstallIn(ApplicationComponent::class)
@Module
interface Module {
@Binds
fun bindWebRepository(repository: WebRepositoryImpl): WebRepository
@Binds
fun bindLocalRepository(repository: LocalRepositoryImpl): LocalRepository
}
It tells Dagger that if you need WebRepository
dependency then it must provide WebRepositoryImpl
and the same for LocalRepository
and LocalRepositoryImpl
.
What is the use case for @Binds vs @Provides annotation in Dagger2
Upvotes: 4
Reputation: 4742
interface MainRepository {
...
}
interface LocalRepository {
...
}
interface WebRepository {
...
}
class MainRepositoryImpl constructor(
private val localRepository: LocalRepository,
private val webRepository: WebRepository
) : MainRepository {
...
}
class LocalRepositoryImpl constructor(
private val localMapper: LocalMapper
private val popularMovieDao: PopularMovieDao
) : LocalRepository {
...
}
class WebRepositoryImpl constructor(
private val webMapper: WebMapper,
private val popularMovieApi: PopularMovieApi
) : WebRepository {
...
}
@Module
@InstallIn(ApplicationComponent::class)
object RepositoryModule {
@Singleton
@Provides
fun provideMainRepository(
localRepository: LocalRepository,
webRepository: WebRepository
): MainRepository = MainRepositoryImpl(localRepository, webRepository)
@Singleton
@Provides
fun provideLocalRepository(
localMapper: LocalMapper,
popularMovieDao: PopularMovieDao
): LocalRepository = LocalRepositoryImpl(localMapper, popularMovieDao)
@Singleton
@Provides
fun provideWebRepository(
webMapper: WebMapper,
popularMovieApi: PopularMovieApi
): WebRepository = WebRepositoryImpl(webMapper, popularMovieApi)
Try this and tell me if it worked. Since you have provided all your Repositories with @Provides
, Dagger-Hilt knows how to create them. Are you using Room
for your localDatabase? If yes, then creating the Database like you did might not be right. If you're not using Room
that you should start to, as it makes your life easier.
Here is the right way to create a room database with dagger hilt:
@Entity(tableName = "exampleTableName")
data class ExampleEntity(
@PrimaryKey(autoGenerate = true)
val id: Int,
// ... whatever you need
val header: String = "",
val title: String = "",
val description: String = "",
)
@Database(entities = [ExampleEntity::class], version = 1)
abstract class ExampleDatabase : RoomDatabase() {
abstract fun exampleDao(): ExampleDao
companion object {
const val DATABASE_NAME = "example_db"
}
}
@Dao
interface DocumentDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(exampleEntity: List<ExampleEntity>)
@Query("SELECT * FROM exampleTableName")
suspend fun getList(): List<ExampleEntity>
}
@Module
@InstallIn(ApplicationComponent::class)
object RoomModule {
@Singleton
@Provides
fun provideExampleDB(@ApplicationContext context: Context): ExampleDatabase = Room.databaseBuilder(
context,
ExampleDatabase::class.java,
ExampleDatabase.DATABASE_NAME,
).fallbackToDestructiveMigration().build()
@Singleton
@Provides
fun provideExampleDAO(exampleDatabase: ExampleDatabase): ExampleDao = exampleDatabase.exampleDao()
}
Upvotes: 0