Search code examples
androidkotlindependency-injectiondagger-hilt

Android hilt injection cycle error with multiple modules referencing a core module


We currently have 3 modules: App, Api and Core.
App depends on Api and Core.
Api depends on Core.

In our Core module we have a VersionProvider:

class VersionProvider @Inject constructor(@ApplicationContext context: Context) {
    val versionName = context.packageManager.getPackageInfo(context.packageName, 0).versionName

    val versionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        context.packageManager.getPackageInfo(context.packageName, 0).longVersionCode
    } else {
        @Suppress("DEPRECATION")
        context.packageManager.getPackageInfo(context.packageName, 0).versionCode
    }
}

That is injected in classes, both in Api module and App module.

The core module hilt module is defined like this:

@Module
@InstallIn(SingletonComponent::class)
abstract class CoreModule {

    @Singleton
    @Binds
    abstract fun bindVersionProvider(
        provider: VersionProvider
    ): VersionProvider
}

When compiling we get this error:

C:\Code\xxx\app\build\generated\hilt\component_sources\development\com\xxx\App_HiltComponents.java:200: error: [Dagger/DependencyCycle] Found a dependency cycle: public abstract static class SingletonC implements App_GeneratedInjector, ^ com.xxx.core.VersionProvider is injected at com.xxx.core.hilt.CoreModule.bindVersionProvider(provider) com.xxx.core.VersionProvider is injected at com.xxx.core.hilt.CoreModule.bindVersionProvider(provider) ... The cycle is requested via: com.xxx.core.VersionProvider is injected at com.xxx.api.core.hilt.ApiClientModule.bindNetworkManager(�, versionProvider) com.xxx.api.services.helpers.INetworkManager is injected at com.xxx.api.core.hilt.ApiClientModule.bindInventoryApi(networkManager) com.xxx.api.services.inventory.InventoryApi is injected at com.xxx.api.services.inventory.InventoryService(api, �) com.xxx.api.services.inventory.InventoryService is injected at com.xxx.api.core.hilt.ServiceModule.bindInventoryService(service) com.xxx.api.services.inventory.IInventoryService is injected at com.xxx.managers.inventory.InventoryManager(inventoryService, �) com.xxx.managers.inventory.InventoryManager is injected at com.xxx.core.hilt.ManagerModule.bindInventoryManager(manager) com.xxx.managers.inventory.IInventoryManager is injected at com.xxx.App.inventoryManager com.xxx.App is injected at com.xxx.App_GeneratedInjector.injectApp(com.xxx.App) The following other entry points also depend on it: dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.ViewModelFactoriesEntryPoint.getHiltViewModelMap() [com.xxx.App_HiltComponents.SingletonC ? com.xxx.App_HiltComponents.ActivityRetainedC ? com.xxx.App_HiltComponents.ViewModelC] 1 error

In the App and API module the Hilt module is defined in the same way e.g.:

@Module
@InstallIn(SingletonComponent::class)
object ApiClientModule {
    @Provides
    @Singleton
    fun bindNetworkManager(
        settings: ISettings,
        versionProvider: VersionProvider
    ): INetworkManager {
        return NetworkManager(settings, versionProvider)
    }
...
}

I think the problem has to do with the fact that VersionProvider is somehow registered mulitple times in the Hilt container as it is referenced both from the App and Api modules.
But I don't know what Hilt configuration I am missing to make it work.
Any clues?


Solution

  • I think the dependency cycle occurs in the CoreModule. Try removing this:

        @Singleton
        @Binds
        abstract fun bindVersionProvider(
            provider: VersionProvider
        ): VersionProvider
    

    And annotating the VersionProvider class with @Singleton.