Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access Dagger subcomponent dependencies from parent android module

Recently I started to divide our application into smaller Android modules, but I'm having a hard time to make Dagger work the way I want it to.

My current dagger setup consist of:
- ApplicationComponent marked with @Singleton. This component is created on app start.
- UserSubComponent marked with @UserScope. This subcomponent is created when the user login.

Both these components is placed in my app module together with my App class who's responsible for creating both components.

In my login module (Which is a parent to my app module, so it can't access anything in the app module) I have my AuthenticationManager. When the user login I use RxJava to signal from my AuthenticationManager to App, so the UserSubComponent can be created.

My problem is that I need to access some dependencies from my UserSubComponent, after it have been created, in my AuthenticationManager so I can preload the user's data before moving on.

Module structure:

              app (AppComponent & UserSubComponent)
                                ^
                                |
  login (AuthenticationManager) - feature 2 - feature 3

My App 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)
                }
    }
}

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

App component

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

    fun userComponentBuilder(): UserComponent.Builder
}

AppModule

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

UserSubComponent

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

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

}

UserModule

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

Can I somehow get this structure to work? Or what are my options when it comes to modules + dagger?

like image 220
Eixx Avatar asked Dec 06 '18 14:12

Eixx


People also ask

Can subcomponent have multiple parents Android?

While dependent components can have 1 or more parents SubComponent can only have one.

What is subcomponent in dagger?

In Dagger 2, component is the main container-like object that binds all the dependencies (or it's factory). Subcomponent are components that is like an extension to its parent component. It can be used for. Partition the dependencies into different compartments.

How do you communicate between modules in Android?

There are two ways to communicate between Modules in Android: Using Callbacks/ Interfaces. Using Local Broadcast.


1 Answers

So after a lot of trying, I finally managed to solve my problem.

What I discovered was:

  • Don't use SubComponents when your app is divided into multiple modules.
  • Each module needs it's own component (feature component)

I found this article really helpful: https://proandroiddev.com/using-dagger-in-a-multi-module-project-1e6af8f06ffc

like image 128
Eixx Avatar answered Sep 28 '22 02:09

Eixx