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

时间:2018-12-06 14:32:31

标签: android module dagger-2 dagger

最近,我开始将应用程序划分为较小的Android模块,但是我很难使Dagger以我希望的方式工作。

我当前的匕首设置包括:
-标记为ApplicationComponent的{​​{1}}。此组件是在应用启动时创建的。
-标记为@Singleton的{​​{1}}。该子组件是在用户登录时创建的。

这两个组件与负责创建两个组件的UserSubComponent类一起放置在我的@UserScope模块中。

在我的app模块中(这是我的应用程序模块的父级,因此它无法访问应用程序模块中的任何内容),我有App。 当用户登录时,我使用RxJava从我的loginAuthenticationManager发出信号,因此可以创建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
    }

}

我能以某种方式使这种结构起作用吗?或关于模块+匕首,我有什么选择?

2 个答案:

答案 0 :(得分:0)

当Dagger尝试创建AuthenticationManager的对象时,它也会尝试注入任何带有@Inject注释的字段。正如您正确指出的那样,PreLoader来自不同的作用域,这实际上意味着它来自不同的组件,即UserComponent

此处要注意的重要一点是,UserComponent对象最初是由Dagger创建的,AuthenticationManager对象尚未创建。并且由于PreLoaderUserComponent提供,因此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)

因此,经过大量的尝试,我终于设法解决了我的问题。

我发现的是:

  • 当您的应用分为多个模型时,请勿使用SubComponents。
  • 每个模型都需要它自己的组件(功能组件)

我发现这篇文章真的很有帮助: https://proandroiddev.com/using-dagger-in-a-multi-module-project-1e6af8f06ffc