从父 android 模块访问 Dagger 子组件依赖项
Access Dagger subcomponent dependencies from parent android module
最近我开始将我们的应用程序分成更小的 Android 模块,但我很难让 Dagger 按我想要的方式工作。
我目前的匕首设置包括:
- ApplicationComponent
标记为 @Singleton
。此组件在应用启动时创建。
- UserSubComponent
标记为 @UserScope
。该子组件在用户登录时创建。
这两个组件与负责创建这两个组件的 App
class 一起放在我的 app
模块中。
在我的 login
模块中(它是我的应用程序模块的父级,因此它无法访问应用程序模块中的任何内容)我有我的 AuthenticationManager
。
当用户登录时,我使用 RxJava 将信号从我的 AuthenticationManager
发送到 App
,因此可以创建 UserSubComponent
。
我的问题是我需要从我的 UserSubComponent
访问一些依赖项,在它创建后,在我的 AuthenticationManager
中,这样我就可以在继续之前预加载用户的数据。
模块结构:
app (AppComponent & UserSubComponent)
^
|
login (AuthenticationManager) - feature 2 - feature 3
我的应用class:
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
}
AppModule
@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()
}
我能以某种方式让这个结构发挥作用吗?或者说到模块 + 匕首时我有什么选择?
当 Dagger 尝试创建 AuthenticationManager
的对象时,它也会尝试注入任何 @Inject
注释字段。这是行不通的,因为您正确地指出 PreLoader
来自不同的范围,这实际上意味着它来自不同的组件,即 UserComponent
.
这里需要注意的重要一点是 UserComponent
在 AuthenticationManager
对象最初由 Dagger 创建时尚未创建。由于 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()
}
}
}
您的应用程序 class:
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
}
}
经过多次尝试,终于解决了我的问题。
我发现的是:
- 当您的应用被分成多个模块时,不要使用子组件。
- 每个模块都需要它自己的组件(功能组件)
我发现这篇文章很有帮助:
https://proandroiddev.com/using-dagger-in-a-multi-module-project-1e6af8f06ffc
最近我开始将我们的应用程序分成更小的 Android 模块,但我很难让 Dagger 按我想要的方式工作。
我目前的匕首设置包括:
- ApplicationComponent
标记为 @Singleton
。此组件在应用启动时创建。
- UserSubComponent
标记为 @UserScope
。该子组件在用户登录时创建。
这两个组件与负责创建这两个组件的 App
class 一起放在我的 app
模块中。
在我的 login
模块中(它是我的应用程序模块的父级,因此它无法访问应用程序模块中的任何内容)我有我的 AuthenticationManager
。
当用户登录时,我使用 RxJava 将信号从我的 AuthenticationManager
发送到 App
,因此可以创建 UserSubComponent
。
我的问题是我需要从我的 UserSubComponent
访问一些依赖项,在它创建后,在我的 AuthenticationManager
中,这样我就可以在继续之前预加载用户的数据。
模块结构:
app (AppComponent & UserSubComponent)
^
|
login (AuthenticationManager) - feature 2 - feature 3
我的应用class:
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
}
AppModule
@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()
}
我能以某种方式让这个结构发挥作用吗?或者说到模块 + 匕首时我有什么选择?
当 Dagger 尝试创建 AuthenticationManager
的对象时,它也会尝试注入任何 @Inject
注释字段。这是行不通的,因为您正确地指出 PreLoader
来自不同的范围,这实际上意味着它来自不同的组件,即 UserComponent
.
这里需要注意的重要一点是 UserComponent
在 AuthenticationManager
对象最初由 Dagger 创建时尚未创建。由于 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()
}
}
}
您的应用程序 class:
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
}
}
经过多次尝试,终于解决了我的问题。
我发现的是:
- 当您的应用被分成多个模块时,不要使用子组件。
- 每个模块都需要它自己的组件(功能组件)
我发现这篇文章很有帮助: https://proandroiddev.com/using-dagger-in-a-multi-module-project-1e6af8f06ffc