How can Dagger 2 be used to inject using multiple components into the same object

Stampede10343 picture Stampede10343 · Aug 16, 2016 · Viewed 9.1k times · Source

So I have an ApplicationComponent for injecting singletons into my fragments and presenters, but I'm trying to create a component to inject into the same presenter that the AppComponent does. Something along these lines.

@Component{modules = FileManagerModule.class}
public interface FileManagerComponet
{
    public void inject(MyPresenter presenter);
}

@Component{modules = AppModule.class}
public interface AppComponent
{
    public void inject(MyPresenter presenter);
}

@Module
public class AppModule
{
    private Context appContext;
    @Provides
    @Singleton
    public SharedPreferences preferences()
    {
        return appContext.sharedPreferences();
    }
    ...
}

@Module
public class FileManagerModule
{
    private Context activityContext;
    @Provides
    public FileManager FileManager()
    {
        return new FileManager(activityContext);
    }
    ...
}

Answer

Stampede10343 picture Stampede10343 · Dec 2, 2016

To anyone who can't figure this out, one component must provide all the dependencies to an object. So in my case, I'd have to make the FileManagerComponent be a Subcomponent and ".plus()" it with my AppComponent, or make it dependent on AppComponent and have AppComponent expose Context downstream by having a Context context(); Method that will let components that depend on it have access to a the context it has.

For example:

@Singleton
@Component(modules = {NetworkModule.class, AndroidModule.class})
public interface ApplicationComponent {
    FileManagerComponent plus(FileManagerModule module);
}

@Subcomponent(modules = {FileManagerModule.class})
public interface FileManagerComponent {
    void injectMyActivity(MyFileManagingActivity activity);
}

And you would use it like this (in MyFileManagingActivity):

FileManagerComponent fmc = applicationComponent.plus(new FileManagerModule());
fmc.injectMyActivity(this);

Or if you don't want to use subcomponents something like this:

@Singleton
@Component(modules = {NetworkModule.class, AndroidModule.class})
public interface ApplicationComponent {
    Context context();
    File applicationRootDirectory();
}

// Notice this is ALSO a Component
@Component(modules = {FileManagerModule.class}, dependencies = ApplicationComponent.class)
public interface FileManagerComponent {
    void inject(MyFileManagerActivity activity);
}

Now you have to build your component that depends on app component.

FileManagerComponent fmc = DaggerFileManagerComponent.builder()
                   .applicationComponent(appComponent)
                   .fileManagerModule(new FileManagerModule())
                   .build();
fmc.inject(this);