从父android模块访问Dagger子组件依赖项

从父android模块访问Dagger子组件依赖项,android,module,dagger-2,dagger,Android,Module,Dagger 2,Dagger,最近,我开始将我们的应用程序划分为更小的Android模块,但我很难让Dagger按我希望的方式工作 我当前的匕首设置包括: -ApplicationComponent标记为@Singleton。此组件在应用程序启动时创建。 -UserSubComponent标记为@UserScope。此子组件是在用户登录时创建的 这两个组件与负责创建这两个组件的myapp类一起放置在myapp模块中 在我的登录模块(它是我的应用程序模块的父模块,因此无法访问应用程序模块中的任何内容)中,我有我的Authent

最近,我开始将我们的应用程序划分为更小的Android模块,但我很难让Dagger按我希望的方式工作

我当前的匕首设置包括:
-
ApplicationComponent
标记为
@Singleton
。此组件在应用程序启动时创建。
-
UserSubComponent
标记为
@UserScope
。此子组件是在用户登录时创建的

这两个组件与负责创建这两个组件的my
app
类一起放置在my
app
模块中

在我的
登录
模块(它是我的应用程序模块的父模块,因此无法访问应用程序模块中的任何内容)中,我有我的
AuthenticationManager
。 当用户登录时,我使用RxJava从我的
AuthenticationManager
App
发送信号,这样就可以创建
UserSubComponent

我的问题是,我需要在
UserSubComponent
创建后,在我的
AuthenticationManager
中访问一些依赖项,以便在继续之前预加载用户的数据

模块结构:

              app (AppComponent & UserSubComponent)
                                ^
                                |
  login (AuthenticationManager) - feature 2 - feature 3
我的应用程序类:

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 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()
                }
             }
    }
}
AuthenticationManager:

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()
        }
    }
}
用户子组件

@UserScope
@Subcomponent(modules = [UserModule::class, AndroidSupportInjectionModule::class])
interface UserComponent : AndroidInjector<App> {

    @Subcomponent.Builder
    interface Builder {
        fun build(): UserComponent
    }

}

我能设法让这个结构工作吗?或者,对于模块+dagger,我有什么选择?

当dagger尝试创建
AuthenticationManager
的对象时,它还将尝试插入任何
@inject
注释字段。正如您正确指出的那样,
preload
来自不同的范围,这本质上意味着它来自不同的组件,即
UserComponent

这里需要注意的重要一点是,
UserComponent
尚未在Dagger首先创建的
AuthenticationManager
对象处创建。由于
预加载程序
是由
用户组件
提供的,所以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()
        }
    }
}
@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
    }

}
为了访问
preload
对象,您还需要修改
UserComponent
,如下所示:

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()
        }
    }
}
@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
    }

}
@UserScope
@子组件(模块=[UserModule::class,AndroidSupportInjectModule::class])
接口用户组件:AndroidJector{

fun preload():preload/所以经过多次尝试,我终于解决了我的问题

我发现:

  • 当应用程序分为多个模块时,不要使用子组件
  • 每个模块都需要自己的组件(功能组件)
我发现这篇文章非常有用:

@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
    }

}