【问题标题】:Access Dagger subcomponent dependencies from parent android module从父 android 模块访问 Dagger 子组件依赖项
【发布时间】:2019-05-08 06:47:18
【问题描述】:

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

我目前的匕首设置包括:
- ApplicationComponent 标有 @Singleton。该组件是在应用启动时创建的。
- UserSubComponent 标有@UserScope。该子组件在用户登录时创建。

这两个组件与负责创建这两​​个组件的 App 类一起放在我的 app 模块中。

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

应用组件

@Singleton
@Component(modules = [AppModule::class, AndroidSupportInjectionModule::class])
interface AppComponent : AndroidInjector<App> {

    fun userComponentBuilder(): UserComponent.Builder
}

应用模块

@Module
class AppModule {
    @Provides
    @Singleton
    fun provideLoginApi() = LoginApi()
}

用户子组件

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

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

}

用户模块

@Module
class UserModule {
    @Provides
    @UserScope
    fun providesPreLoader() = PreLoader()
}

我能以某种方式让这个结构工作吗?或者当涉及到模块 + 匕首时,我有什么选择?

【问题讨论】:

    标签: android module dagger-2 dagger


    【解决方案1】:

    所以经过一番尝试,我终于设法解决了我的问题。

    我发现的是:

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

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

    【讨论】:

      【解决方案2】:

      当 Dagger 尝试创建 AuthenticationManager 的对象时,它也会尝试注入任何带有 @Inject 注释的字段。这不起作用,因为您正确指出 PreLoader 来自不同的范围,这本质上意味着它来自不同的组件,即 UserComponent

      这里要注意的重要一点是UserComponent 尚未创建,AuthenticationManager 对象首先由 Dagger 创建。由于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()
              }
          }
      }
      

      您的应用类:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-25
        • 2019-02-12
        相关资源
        最近更新 更多