4

I have the following setup:

@ApplicationScope
@Component(
        dependencies = {AppContextComponent.class, CertUtilsComponent.class, ServiceComponent.class, JobManagerComponent.class})
public interface ApplicationComponent
        extends AppContextComponent, CertUtilsComponent, ServiceComponent, JobManagerComponent {

    void inject(MainActivity mainActivity); //honestly, I won't need this
}

And I have the following subscoped component:

@PresenterScope
@Component(dependencies = {ApplicationComponent.class, PersistenceComponent.class})
public interface PresenterComponent
        extends ApplicationComponent, PersistenceComponent {
    void inject(HomePresenter homePresenter);

    void inject(SendCertificateRequestInteractor sendCertificateRequestInteractor);
}

The problem is that PersistenceComponent has the following component as its dependency:

@Component(dependencies = {JobManagerComponent.class, RealmComponent.class, RepositoryComponent.class}, modules = {PersisterModule.class})
public interface PersisterComponent {
    DummyCertPersister dummyCertPersister();
}

Which uses JobManagerComponent, which is the dependency of the ApplicationComponent.

Unfortunately, this component does not seem to be inherited from ApplicationComponent. I need to explicitly keep track of this component, and provide it for the builder like so.

//INJECTOR
    ApplicationComponent applicationComponent = DaggerApplicationComponent.builder()
            .appContextComponent(appContextComponent)
            .certUtilsComponent(certUtilsComponent)
            .jobManagerComponent(jobManagerComponent)
            .serviceComponent(serviceComponent)
            .build();

    this.jobManagerComponent = jobManagerComponent;
    this.applicationComponent = applicationComponent;
    this.certUtilsComponent = certUtilsComponent;
    this.appContextComponent = appContextComponent;
    this.serviceComponent = serviceComponent;
}

public ApplicationComponent getApplicationComponent() {
    return applicationComponent;
}

public JobManagerComponent getJobManagerComponent() {
    return jobManagerComponent;
}

And provide this through a getter when I build my persistence component:

    PersisterComponent persisterComponent = DaggerPersisterComponent.builder()
            .jobManagerComponent(Injector.INSTANCE.getJobManagerComponent()) //this should be subcomponent
            .realmComponent(realmComponent)
            .repositoryComponent(repositoryComponent)
            .persisterModule(new PersisterModule())
            .build();

I would like to have that JobManagerComponent inherited from ApplicationComponent. I'm guessing I need to make this into a @Subcomponent and provide a provision method for it, but so far, it hasn't worked (I don't get a builder method, but it still doesn't see the jobManager within JobManagerComponent.

Is this possible with @Subcomponent? Or do I need to keep track of the "subcomponents" of ApplicationComponent in case a child component depends on it?

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428

1 Answers1

4

The answer is that I was conceptually wrong about how Components work in Dagger2.

A component should only depend on another component if it subscopes that component. A component with multiple component dependencies cannot depend on scoped components; which means they cannot have scoped modules; which also means they cannot use scopes at all and unless the module keeps a reference to the new instance, you'll get a new instance each time you inject. Which is bad, and not what you want at all.

The proper way is to bind every module of the same scope to the same component. That way, the provided dependencies are accessible within the constructors, and you won't have an issue with sharing the same module within different components as well.

Therefore, the approach in the question is completely wrong.

Use this instead.

Community
  • 1
  • 1
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428