10

I'm pretty new to Dagger 2. I'm trying to implement it in my Android project. I've a Service which needs GoogleApiClient. I'm using Dagger to inject it in this service.

@FragmentScoped
@Component(dependencies = {NetComponent.class, RepositoryComponent.class})
public interface CustomServiceComponent {
    void inject(CustomService customService);
}

@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface NetComponent {
    GoogleApiClient getGoogleApiClient();
}

@Singleton
@Component(modules = {AppModule.class, RepositoryModule.class})
public interface RepositoryComponent {
    DatabaseService getDatabaseService();
}

AppModule, NetModule, and RepositoryModule have methods marked @Singleton @Provides When I build my project I get this error:

The locationServiceComponent depends on more than one scoped component: @Singleton NetComponent @Singleton RepositoryComponent

I understand my LocationComponent cannot depend on two @Singleton scoped components but I need both of them in my service and both need to be @Singleton.

Is there any better alternative to do the same thing?

David Rawson
  • 20,912
  • 7
  • 88
  • 124
crysis
  • 1,514
  • 1
  • 20
  • 35

1 Answers1

10

Be aware that although you may have multiple components marked @Singleton their life cycles will follow those of the class where you retain the reference of the component.

This means if you initialise and retain your NetComponent and RepositoryComponent in an Activity it will follow the life cycle of that Activity and will not truly be an app singleton.

Hence, you probably won't need more than one @Singleton components in an Android app. Consider combining your two Singleton components into one component like this:

@Component(modules = {AppModule.class, NetModule.class, RepositoryModule.class})
@Singleton
public interface AppComponent {
    GoogleApiClient getGoogleApiClient();

    DatabaseService getDatabaseService();
}

Then make sure you retain this @Singleton component at Application level and make it available for use in dependent components that are initialised at the level of Fragment or Activity.

public class MyApp extends Application {

    private final AppComponent appComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        appComponent = DaggerAppComponent.builder()
                           //modules if necessary
                           .build();
    }

    public AppComponent getAppComponent() {
        return appComponent;
    }                   
}

Note that as long as your @FragmentScoped don't have any dependent components themselves, you can still create as many of these as you like.

Note that even though one single component now injects GoogleApiClient and DatabaseService you still achieve separation of concerns because these are provided in separate Dagger 2 Modules.

David Rawson
  • 20,912
  • 7
  • 88
  • 124
  • 1
    It's dirty this solution. You AppComponent share all modules, instead I want to be able to compose my Component from many others depending on required configurations and need of provided component. How to do that? crysis introducet well structure – murt Aug 07 '17 at 10:14
  • @murt he's trying to provide singleton dependencies at a non-singleton scope. That won't work. You are right he needs to restructure, but he needs to group Components by scope - a single app-scoped component and then subcomponents or dependent components at the level of Activity or Fragment. – David Rawson Aug 07 '17 at 10:20
  • @murt you can look at some of the other answers using dependent components https://stackoverflow.com/a/40751767/5241933 – David Rawson Aug 07 '17 at 10:21