最近,我开始将应用程序划分为较小的Android模块,但是我很难使Dagger以我希望的方式工作。
我当前的匕首设置包括:
-标记为ApplicationComponent
的{{1}}。此组件是在应用启动时创建的。
-标记为@Singleton
的{{1}}。该子组件是在用户登录时创建的。
这两个组件与负责创建两个组件的UserSubComponent
类一起放置在我的@UserScope
模块中。
在我的app
模块中(这是我的应用程序模块的父级,因此它无法访问应用程序模块中的任何内容),我有App
。
当用户登录时,我使用RxJava从我的login
到AuthenticationManager
发出信号,因此可以创建AuthenticationManager
。
我的问题是,App
创建后,我需要在UserSubComponent
中访问我的UserSubComponent
的某些依赖项,以便在继续操作之前预先加载用户的数据。
模块结构:
AuthenticationManager
我的应用程序类别:
app (AppComponent & UserSubComponent)
^
|
login (AuthenticationManager) - feature 2 - feature 3
AuthenticationManager:
class App : DaggerApplication() {
@Inject
lateinit var authenticationManager: AuthenticationManager
override fun onCreate() {
super.onCreate()
authenticationManager
.authenticationStateStream
.subscribe { state ->
if (state == AuthenticationState.AUTHENTICATED) {
AppInjector.userComponent.inject(this)
}
}
}
应用程序组件
class AuthenticationManager @Inject constructor(loginApi: LoginApi) {
@Inject
lateinit var preLoader : PreLoader // This won't work because of different scope
val authenticationStateStream = Observable<AuthenticationState>()
fun login() {
if (success) {
authenticationStateStream.emit(AuthenticationState.AUTHENTICATED)
// UserSubComponent is now created
preLoader.preload()
}
}
}
AppModule
@Singleton
@Component(modules = [AppModule::class, AndroidSupportInjectionModule::class])
interface AppComponent : AndroidInjector<App> {
fun userComponentBuilder(): UserComponent.Builder
}
UserSubComponent
@Module
class AppModule {
@Provides
@Singleton
fun provideLoginApi() = LoginApi()
}
UserModule
@UserScope
@Subcomponent(modules = [UserModule::class, AndroidSupportInjectionModule::class])
interface UserComponent : AndroidInjector<App> {
@Subcomponent.Builder
interface Builder {
fun build(): UserComponent
}
}
我能以某种方式使这种结构起作用吗?或关于模块+匕首,我有什么选择?
答案 0 :(得分:0)
当Dagger尝试创建AuthenticationManager
的对象时,它也会尝试注入任何带有@Inject
注释的字段。正如您正确指出的那样,PreLoader
来自不同的作用域,这实际上意味着它来自不同的组件,即UserComponent
。
此处要注意的重要一点是,UserComponent
对象最初是由Dagger创建的,AuthenticationManager
对象尚未创建。并且由于PreLoader
由UserComponent
提供,因此Dagger无法注入该字段。但是,您可以自己将该字段注入AuthenticationManager
。
类似这样的东西:
class AuthenticationManager @Inject constructor(loginApi: LoginApi) {
// Remove the @Inject annotation and provide a custom setter which will pre-load user data
private lateinit var preLoader : PreLoader
set(preLoader) {
field = preLoader
preLoader.preload()
}
val authenticationStateStream = Observable<AuthenticationState>()
fun login() {
if (success) {
authenticationStateStream.emit(AuthenticationState.AUTHENTICATED)
// UserSubComponent is now created
// You can't do this here:
// preLoader.preload()
}
}
}
您的App类别:
class App : DaggerApplication() {
@Inject
lateinit var authenticationManager: AuthenticationManager
override fun onCreate() {
super.onCreate()
authenticationManager
.authenticationStateStream
.subscribe { state ->
if (state == AuthenticationState.AUTHENTICATED) {
// Here you can directly set the PreLoader object yourself
authenticationManager.preLoader =
AppInjector.userComponent.preLoader()
}
}
}
}
要访问PreLoader
对象,还需要像这样修改UserComponent
:
@UserScope
@Subcomponent(modules = [UserModule::class, AndroidSupportInjectionModule::class])
interface UserComponent : AndroidInjector<App> {
fun preLoader() : PreLoader // <-- Need to add this
@Subcomponent.Builder
interface Builder {
fun build(): UserComponent
}
}
答案 1 :(得分:0)
因此,经过大量的尝试,我终于设法解决了我的问题。
我发现的是:
我发现这篇文章真的很有帮助: https://proandroiddev.com/using-dagger-in-a-multi-module-project-1e6af8f06ffc