简体   繁体   中英

Dagger2 dependency Cycle by Using @Binds and @Inject fields

I am getting a dependency cycle whenever I try to use a subcomponent with binding objects. I have an app scope and an activity scope. At the app scope I create my web service then when the activity opens I want to create a storage object, controller, and navigator (all custom classes not androidx classes) and inject them into my androidx ViewModel class. But when I do so I get a dependency cycle.

My top level component looks like

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

  val activityComponentBuilder: ActivityComponent.Builder
}

@Module(subcomponents = [ActivityComponent::class])
interface AppModule {

  @Binds
  fun mockWebService(mockWebService: MockWebService): MockWebService
}

Next my subcomponent looks like

@ActivityComponent
@Subcomponent(modules = [ActivityModule::class])
interface ActivityComponent {

  fun inject(sharedViewModel: SharedViewModel)

  @Subcomponent.Builder
  interface Builder {
    @BindsInstance
    fun storage(storage: Storage): Builder

    fun build(): ActivityComponent
  }
}

In my activity module I bind two objects

  @Binds
  abstract fun controller(controller: Controller): Controller

  @Binds
  abstract fun navigator(navigator: Navigator): Navigator

Each object has an @Inject constructor

class Navigator @Inject constructor(private val storage: Storage)

class Controller @Inject constructor(
  private val webService: MockWebService,
  private val navigator: Navigator,
  private val storage: Storage
) {

Inside my shared view model I try to build my component and inject the fields

  @Inject
  lateinit var navigator: Navigator
  @Inject
  lateinit var controller: Controller

  init {
      MainApplication.component.activityComponentBuilder
        .storage(InMemoryStorage.from(UUID.randomUUID().toString()))
        .build()
        .inject(this)

  }

But dagger won't build. I get an error

[Dagger/DependencyCycle] Found a dependency cycle: public abstract interface AppComponent {

MockWebService is injected at di.AppModule.mockWebService(mockWebService)
MockWebService is injected at ActivityModule.Controller(webService, …)
Controller is injected at SharedViewModel.controller
SharedViewModel is injected at

But the error message cuts off there. Am I missing something in how to use a subcomponent to put objects on the graph and then inject them into an object? Is this not possible with Dagger?

@Binds is used to let dagger know the different implementations of an interface. You don't need @Binds here since Navigator and Controller are simple classes that do not implement any interface. I'd assume that's the case with MockWebService too. Also, those classes have @Inject constructor , which means dagger can instantiate them and we don't need to write extra @Provides functions for those classes.

@Binds isn't doing any scoping. Its only job is to tell dagger about different implementations. You can add @XScope with @Binds to make some object scoped. Or, you could just add the scope annotation to the class declaration. Here's an example of how you can add scope to class declaration.

As for the dependency cycle, I think it's because you're telling ActivityComponent to use ActivityModule and telling ActivityModule to install ActivityComponent . Doing just either one should be the case (I think).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM