15

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);
    }
    ...
}
Stampede10343
  • 844
  • 1
  • 6
  • 21
  • 2
    This question has been asked multiple times, a component has to provide _all_ of the fields, or it won't work. You can't mix and match components. e.g. check here: http://stackoverflow.com/a/38897722/1837367 – David Medenjak Aug 16 '16 at 16:09
  • @DavidMedenjak Then how can I give the FileManagerModule an activity context if the AppComponent is being built when the application is created and there is no activity context? – Stampede10343 Aug 16 '16 at 17:02

1 Answers1

20

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);
Stampede10343
  • 844
  • 1
  • 6
  • 21
  • 2
    It would be great if you could add the code here. Because the official docs and examples for sub components are too hard to understand – eC Droid Jul 19 '17 at 09:16
  • @Stampede10343: What if I my `FileManagerModule` `include` another module. I am getting `[Dagger/SubcomponentFactoryMethodMissingModule]`. What am I missing ? – theapache64 Dec 28 '18 at 16:15