Как можно использовать Dagger 2 для внедрения нескольких компонентов в один и тот же объект

Итак, у меня есть ApplicationComponent для внедрения синглетонов в мои фрагменты и презентеры, но я пытаюсь создать компонент для внедрения в тот же презентатор, что и AppComponent. Что-то в этом роде.

@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);
    }
    ...
}

person Stampede10343    schedule 16.08.2016    source источник
comment
Этот вопрос задавался несколько раз, компонент должен предоставить все поля, иначе он не будет работать. Вы не можете смешивать и сочетать компоненты. например проверьте здесь: stackoverflow.com/a/38897722/1837367   -  person David Medenjak    schedule 16.08.2016
comment
@DavidMedenjak Тогда как я могу дать FileManagerModule контекст действия, если AppComponent создается при создании приложения, а контекст действия отсутствует?   -  person Stampede10343    schedule 16.08.2016


Ответы (1)


Для тех, кто не может понять это, один компонент должен предоставлять все зависимости для объекта. Так что в моем случае мне пришлось бы сделать FileManagerComponent подкомпонентом и ".plus()" его с моим AppComponent или сделать его зависимым от AppComponent и заставить AppComponent выставлять контекст ниже по течению, имея метод Context context();, который позволит компонентам, которые зависят от него иметь доступ к контексту, который у него есть.

Например:

@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);
}

И вы бы использовали это так (в MyFileManagingActivity):

FileManagerComponent fmc = applicationComponent.plus(new FileManagerModule());
fmc.injectMyActivity(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);
}

Теперь вам нужно создать свой компонент, который зависит от компонента приложения.

FileManagerComponent fmc = DaggerFileManagerComponent.builder()
                   .applicationComponent(appComponent)
                   .fileManagerModule(new FileManagerModule())
                   .build();
fmc.inject(this);
person Stampede10343    schedule 02.12.2016
comment
Было бы здорово, если бы вы добавили код сюда. Потому что официальные документы и примеры для подкомпонентов слишком сложны для понимания. - person eC Droid; 19.07.2017
comment
@ Stampede10343: Что, если я использую FileManagerModule include другой модуль. Я получаю [Dagger/SubcomponentFactoryMethodMissingModule]. Что мне не хватает? - person theapache64; 28.12.2018