尝试使用匕首解决依赖循环
Trying to solve a dependency cycle using 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 这样我就可以将其用作回调。
class LoginPresenterImp(private val loginRequest: LoginRequest) :
BasePresenterImp<LoginView>(),
LoginPresenter,
LoginResponseListener {
}
并且 loginResponseListener 在这里传递:
class LoginRequestImp(
private val loginUser: LoginUser,
private val loginResponseListener: LoginResponseListener)
: LoginRequest {
}
非常感谢,
如评论中Ayush所述:
You need LoginResponseListener to create LoginRequest and you need LoginRequest to create LoginResponseListener. So, you are getting the error.
When you are creating LoginRequest in LoginRequestImp(loginUser, loginPresenter), loginPresenter is a parameter to the constructor of type LoginResponseListener. You should try to eliminate this dependency. May be you can set the listener later from the presenter
在这些评论之间的回复中:
LoginRequest has been created in provideLoginRequest
但这就是正在发生的事情:
- 您的 LoginFragment 试图注入 LoginPresenter。
- 在注入 LoginPresenter 之前,您需要创建一个 LoginRequest。
- 在创建 LoginRequest 之前,您需要一个 LoginUser 和一个 LoginRequestListener。
- 在创建 LoginRequestListener(已作为 LoginPresenterImpl 实现)之前,您需要一个 LoginRequest。
- 您正在创建登录请求,因此 Dagger 放弃并正确报告循环引用。
重申一下:即使您使用接口正确设置了绑定,Dagger 也无法创建它们中的任何一个,因为要调用其中一个构造函数,它必须创建另一个构造函数。这不是 Dagger 的问题:如果 class A 的构造函数采用 B 的实例,并且 class B 的构造函数采用 A 的实例,那么在尊重它们的同时,你也不能手动构造它们中的任何一个构造函数参数。
正如 Ayush 所建议的,不要让 LoginRequest 注入 LoginResponseListener。相反,创建一个类似于 setLoginResponseListener
的方法,LoginPresenterImp 可以调用该方法。我也推荐这种方法,部分原因是 :您要绝对确保充当 LoginPresenter 的 LoginPresenterImp 实例与充当 LoginResponseListener 的实例相同。
作为替代方案,您可以注入 Provider<LoginPresenter>
而不是 LoginResponseListener
,并更改 LoginRequestImp 以接受 Provider。 (您也可以注入 Provider<LoginResponseListener>
,但如果您希望 LoginResponseListener 与您的 LoginPresenter 实例相同,则不应显式调用 LoginPresenterImp 构造函数。您需要切换到 @Binds
理想情况下,或者至少让您的 @Provides
方法注入 LoginPresenter。)您可以注入 Provider,因为 a Provider<T>
is automatically bound for every class <T>
that Dagger knows how to provide, and it solves your problem because Dagger can pass a Provider<T>
without trying to create the T
. This will technically appear to work even if you leave your bindings as @Reusable
, but in a multithreaded environment @Reusable
isn't going to guarantee that you always receive the same instance for LoginRequestListener as your LoginPresenter, or that you'll receive a new LoginPresenter for every LoginFragment. If you want to guarantee that, you can look into custom scopes.
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 这样我就可以将其用作回调。
class LoginPresenterImp(private val loginRequest: LoginRequest) :
BasePresenterImp<LoginView>(),
LoginPresenter,
LoginResponseListener {
}
并且 loginResponseListener 在这里传递:
class LoginRequestImp(
private val loginUser: LoginUser,
private val loginResponseListener: LoginResponseListener)
: LoginRequest {
}
非常感谢,
如评论中Ayush所述:
You need LoginResponseListener to create LoginRequest and you need LoginRequest to create LoginResponseListener. So, you are getting the error.
When you are creating LoginRequest in LoginRequestImp(loginUser, loginPresenter), loginPresenter is a parameter to the constructor of type LoginResponseListener. You should try to eliminate this dependency. May be you can set the listener later from the presenter
在这些评论之间的回复中:
LoginRequest has been created in provideLoginRequest
但这就是正在发生的事情:
- 您的 LoginFragment 试图注入 LoginPresenter。
- 在注入 LoginPresenter 之前,您需要创建一个 LoginRequest。
- 在创建 LoginRequest 之前,您需要一个 LoginUser 和一个 LoginRequestListener。
- 在创建 LoginRequestListener(已作为 LoginPresenterImpl 实现)之前,您需要一个 LoginRequest。
- 您正在创建登录请求,因此 Dagger 放弃并正确报告循环引用。
重申一下:即使您使用接口正确设置了绑定,Dagger 也无法创建它们中的任何一个,因为要调用其中一个构造函数,它必须创建另一个构造函数。这不是 Dagger 的问题:如果 class A 的构造函数采用 B 的实例,并且 class B 的构造函数采用 A 的实例,那么在尊重它们的同时,你也不能手动构造它们中的任何一个构造函数参数。
正如 Ayush 所建议的,不要让 LoginRequest 注入 LoginResponseListener。相反,创建一个类似于 setLoginResponseListener
的方法,LoginPresenterImp 可以调用该方法。我也推荐这种方法,部分原因是
作为替代方案,您可以注入 Provider<LoginPresenter>
而不是 LoginResponseListener
,并更改 LoginRequestImp 以接受 Provider。 (您也可以注入 Provider<LoginResponseListener>
,但如果您希望 LoginResponseListener 与您的 LoginPresenter 实例相同,则不应显式调用 LoginPresenterImp 构造函数。您需要切换到 @Binds
理想情况下,或者至少让您的 @Provides
方法注入 LoginPresenter。)您可以注入 Provider,因为 a Provider<T>
is automatically bound for every class <T>
that Dagger knows how to provide, and it solves your problem because Dagger can pass a Provider<T>
without trying to create the T
. This will technically appear to work even if you leave your bindings as @Reusable
, but in a multithreaded environment @Reusable
isn't going to guarantee that you always receive the same instance for LoginRequestListener as your LoginPresenter, or that you'll receive a new LoginPresenter for every LoginFragment. If you want to guarantee that, you can look into custom scopes.