0

I create dagger2 Conponent and Subcomponent

Main Component:

@Singleton
@Component(modules = {PresentersModule.class, RepositoriesModule.class, UtilsModule.class, AppModule.class, RoomModule.class})
public interface AppComponent {

    SettingsComponent plusSettingsComponent(NetworkModule networkModule);
...

My subcomponent:

@Upgradable
@Subcomponent(modules = {NetworkModule.class})
public interface SettingsComponent {
    RestApiFactory getRestApiFactory();
}

I want set RestApiFactory from subcomponent like parameter in main component

@Singleton
    @Provides
    TransactionsRepository provideTransactionsRepository(RestApiFactory restApiFactory) {
        return new TransactionsRepositoryImpl(restApiFactory);
    }

but RestApiFactory contains in Subcomponent

Now I make this- in Application class I have method:

public SettingsComponent plusSettingsComponent() {
        if (settingsComponent == null) {
            settingsComponent = appComponent.plusSettingsComponent(new NetworkModule());
        }
        return settingsComponent;
    }

And call it in repository:

return MyApplication.me().plusSettingsComponent().getRestApiFactory()
                .getTransactionsService()
                .getTransactions(transactionRequest, page);

if I try set RestApiFactory like parameter - I get error:

I cahge method to this:

@Singleton
    @Provides
    TransactionsRepository provideTransactionsRepository(RestApiFactory restApiFactory) {
        return new TransactionsRepositoryImpl(restApiFactory);
    }

And change this:

private RestApiFactory restApiFactory;

    @Inject
    public TransactionsRepositoryImpl(RestApiFactory restApiFactory) {
        this.restApiFactory = restApiFactory;
    }

    @Override
    public Observable<List<TransactionItem>> loadTransactions(TransactionRequest transactionRequest, int page) {
        return restApiFactory.getTransactionsService()
                .getTransactions(transactionRequest, page);
    }

Error

Error:(30, 27) error: retrofit2.Retrofit cannot be provided without an @Inject constructor or from an @Provides-annotated method.

full error

Error:(30, 27) error: retrofit2.Retrofit cannot be provided without an @Inject constructor or from an @Provides-annotated method.
retrofit2.Retrofit is injected at
my.network.api.RestApiFactory.<init>(retrofit)
my.network.api.RestApiFactory is injected at
my.dagger.RepositoriesModule.provideTransactionsRepository(restApiFactory)
my.repositories.TransactionsRepository is injected at
my.dagger.PresentersModule.provideTransactionsPresenter(…, transactionsRepository)
my.presenters.TransactionsPresenter is provided at
my.dagger.AppComponent.getTransactionsPresenter()
A binding with matching key exists in component: my.dagger.SettingsComponent
ip696
  • 6,574
  • 12
  • 65
  • 128
  • Can you post your NetworkModule? It seems you try to inject something that you haven't declared – Eselfar Jan 11 '18 at 14:33
  • 1
    Please update your question to include the full error message and the related code. Your current question does not reference `Retrofit` anywhere other than the error message, but the error would indicate that you try to inject it somewhere. You can find a generic answer to your question here, as well as an example on what to include in your question: https://stackoverflow.com/q/44912080/1837367 – David Medenjak Jan 11 '18 at 14:33
  • @ David Medenjak I added full error – ip696 Jan 11 '18 at 14:46
  • I haven't used subcomponents on dagger2 and I'm a bit lost in wahat you try to do. What are you trying to inject? It's not clear. What I did to get my retrofit instance is to create a ``@Provides`` method where instantiate, create interceptors, etc. – Gonzalo Jan 11 '18 at 15:06

1 Answers1

0

Look at the stacktrace of the error message:

Error:(30, 27) error: retrofit2.Retrofit cannot be provided without an @Inject constructor or from an @Provides-annotated method.
retrofit2.Retrofit is injected at
my.network.api.RestApiFactory.<init>(retrofit)
my.network.api.RestApiFactory is injected at
my.dagger.RepositoriesModule.provideTransactionsRepository(restApiFactory)
my.repositories.TransactionsRepository is injected at
my.dagger.PresentersModule.provideTransactionsPresenter(…, transactionsRepository)
my.presenters.TransactionsPresenter is provided at
my.dagger.AppComponent.getTransactionsPresenter()
A binding with matching key exists in component: my.dagger.SettingsComponent

It says you are injecting Retrofit at RestApiFactory.

RestApiFactory is provided in your RepositoriesModule when you provide TransactionsRepository

TransactionsRepository, in turn, is injected in your PresentersModule which you use to provide in the provision method getPresenter of your AppComponent.

So it seems you are trying to use a binding from a sub-component (Retrofit bound in SettingsComponent) in a super-component (AppComponent). This explains the "binding key exists in SettingsComponent error message - Retrofit is indeed bound but not in the correct way.

You can't use bindings from sub-components in super-components - dependencies bubble down rather than float upwards. Dependencies you want to use in multiple sub-components should be bound at the top-level and exposed to sub-components.

David Rawson
  • 20,912
  • 7
  • 88
  • 124