I am creating an Android Application based on Clean Archtecture with App Modularization.
I have modularized the app by 4 layers (:presentation, :domain:, :data, commons). The required hierarchy is as follows
- :presentation can access :commons + :domain
- :domain can access :commons
- :data can access :commons + :domain
- :commons access no other module
Problem?
I have added The HILT MODULE in :data module as it belongs there because of dependency nature. It implements the RestaurantRepository Interface defined in :domain module.
@Module
@InstallIn(SingletonComponent::class)
object DataDependenciesModule {
@Singleton
@Provides
fun providesRestaurantRepository(
api: RestaurantApi,
localCacheRepository: LocalCacheRepository,
database: MealBookingDatabase
): RestaurantRepository {
return RestaurantRepositoryImpl(api, localCacheRepository, database)
}
Below is the UseCase which uses/requires this dependency is inside :domain module (Ofcourse UseCases lies in :domain modue), but the dependency is not accessible there.
class GetRestaurants @Inject constructor(
private val repository: RestaurantRepository,
) {
suspend operator fun invoke(
fetchFromApi: Boolean,
): Flow<Resource<List<Restaurant>>> {
return repository.getRestaurants(fetchFromApi)
}
}
Possible Soltuions
make :domain module include :data module, hence :data stuff can be accessible in :domain. (Can't do that, as :data already depends on :domain, it will generate a circular dependency)
Add HILT MODULE and entire Dependency Injection stuff in :presentation and make :presentation include :data module (to create dependencies). I believe it is a bad approach as this way we will be exposing :data to :presentation, and :presentation clearly doesn't needs to have access to whats happening inside :data.
Include DI in commons, and include commons in all modules, but how can we do that :commons will also require to include classes which are in other modules to create them.
What is Required?
Make RestaurantRepository accessible in GetRestaurants Use Case inside :domain, maybe any Interceptor can be created here which i don't have any idea about.
What is the best approach to handle this type of Dependency Injection requirement?
Any help will be highly appreciated.
It is not a must to create DI dir in :data, meaning like
DI can also have a dir in their hierarchy.
api: RestaurantApi, localCacheRepository: LocalCacheRepository, database: MealBookingDatabaseall of these parameters should be singleton injectables similar to the.@Module @InstallIn(SingletonComponent::class) object DataDependenciesModule.And this class of yoursRestaurantRepositoryImplwill have an injectable constructor. Then after all that when you inject your interface in GetRestaurants use case it will be available. Just a tip any injectable that is to be placed in Usecase can have ViewModelComponent. Hope it helps