How to setup HILT DI in layer base multi-module android application

413 Views Asked by At

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

  1. :presentation can access :commons + :domain
  2. :domain can access :commons
  3. :data can access :commons + :domain
  4. :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

  1. 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)

  2. 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.

  3. 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.

2

There are 2 best solutions below

0
Muslim 9d On

It is not a must to create DI dir in :data, meaning like

  1. :data
  2. :domain
  3. :presentation
  4. :di

DI can also have a dir in their hierarchy. api: RestaurantApi, localCacheRepository: LocalCacheRepository, database: MealBookingDatabase all of these parameters should be singleton injectables similar to the. @Module @InstallIn(SingletonComponent::class) object DataDependenciesModule. And this class of yours RestaurantRepositoryImpl will 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

0
ObscureCookie On

I solved this issue by including hilt modules in :app module as it includes all modules you defined.