尝试使用匕首解决依赖周期

时间:2019-01-02 16:22:24

标签: android dagger-2 dagger

dagger-android 2.16

我的Dagger模块中有一个依赖周期错误。我想我知道问题出在哪里,但不确定如何解决。

这是错误消息:

Found a dependency cycle:
  public interface LoginFragmentSubcomponent extends AndroidInjector<LoginFragment> {
     presentation.login.request.LoginRequest is injected at
              mobileui.login.di.LoginActivityModule.provideLoginResponseListener(…, loginRequest)
          presentation.login.response.LoginResponseListener is injected at
              mobileui.login.di.LoginActivityModule.provideLoginRequest(…, loginPresenter)
          presentation.login.request.LoginRequest is injected at
              mobileui.login.di.LoginActivityModule.provideLoginPresenter(…, loginRequest)
          mobileui.login.LoginPresenter is injected at
              mobileui.login.LoginFragment.loginPresenter

这是我收到错误的以下模块

@Module
class LoginActivityModule {
    @Reusable
    @Provides
    fun provideLoginPresenter(loginRequest: LoginRequest): LoginPresenter {
        return LoginPresenterImp(loginRequest)
    }

    @Reusable
    @Provides
    fun provideLoginResponseListener(loginRequest: LoginRequest): LoginResponseListener {
        LoginPresenterImp(loginRequest)
    }

    @Reusable
    @Provides
    fun provideLoginRequest(loginUser: LoginUser,
                            loginPresenter: LoginResponseListener): LoginRequest {
        return LoginRequestImp(loginUser, loginPresenter)
    }
}

我的LoginPresenterImp实现了LoginResponseListener,我想将其传递给LoginRequestImp类,以便可以将其用作回调。

class LoginPresenterImp(private val loginRequest: LoginRequest) :
    BasePresenterImp<LoginView>(),
    LoginPresenter,
    LoginResponseListener {
}

loginResponseListener在这里传递:

class LoginRequestImp(
    private val loginUser: LoginUser,
    private val loginResponseListener: LoginResponseListener)
    : LoginRequest {
}

在此先感谢

1 个答案:

答案 0 :(得分:4)

如评论中所述的Ayush

  

您需要LoginResponseListener来创建LoginRequest,并且需要LoginRequest来创建LoginResponseListener。因此,您遇到了错误。

     

在LoginRequestImp(loginUser,loginPresenter)中创建LoginRequest时,loginPresenter是类型LoginResponseListener的构造函数的参数。您应该尝试消除这种依赖性。也许稍后您可以从演示者设置监听器

在这些评论之间的回复中:

  

LoginRequest已在ProvideLoginRequest中创建

但这是正在发生的事情

  1. 您的LoginFragment尝试注入LoginPresenter。
  2. 在注入LoginPresenter之前,您需要创建一个LoginRequest。
  3. 在创建LoginRequest之前,您需要一个LoginUser和一个LoginRequestListener。
  4. 在创建LoginRequestListener(已实现为LoginPresenterImpl)之前,您需要一个LoginRequest。
  5. 您正在创建LoginRequest,因此Dagger放弃并正确报告了循环引用。

重申一下:即使您已正确使用接口设置了绑定,Dagger也无法创建任何接口,因为调用任何一个构造函数都必须创建另一个。这不是Dagger的问题:如果类A的构造函数采用B的实例,而类B的构造函数采用A的实例,则您在尊重其构造函数参数的同时也无法手动构造它们中的任何一个。


正如Ayush建议的那样,不要让LoginRequest注入LoginResponseListener。而是创建一个setLoginResponseListener之类的方法,LoginPresenterImp可以调用该方法。我也推荐这种方法,部分原因是@Reusable has weaker semantics than you want:您要绝对确保充当LoginPresenter的LoginPresenterImp实例与充当LoginResponseListener的实例相同。

作为替代方案,您可以注入Provider<LoginPresenter>而不是LoginResponseListener,并将LoginRequestImp更改为也接受提供者。 (您也可以注入Provider<LoginResponseListener>,但是如果希望LoginResponseListener与LoginPresenter实例相同,则不应显式调用LoginPresenterImp构造函数。您想切换到@Binds理想情况下,或者至少让您的@Provides方法注入LoginPresenter。)由于a Provider<T> is automatically bound for every class <T> that Dagger knows how to provide,您被允许注入Provider,它可以解决您的问题,因为Dagger可以传递Provider<T>而无需尝试创建T。即使您将绑定保留为@Reusable,从技术上讲,这似乎仍然有效,但是在多线程环境中,@Reusable不能保证您总是收到与LoginPresenter相同的LoginRequestListener实例,或者您将为每个LoginFragment收到一个新的LoginPresenter。如果您想保证这一点,可以查看custom scopes