Dagger 2 Добавление подкомпонента к родительскому компоненту

Привет, сообщество. У меня проблема с пониманием того, что кинжал 2 добавляет субкомпонент новым способом (добавлен в кинжал 2.7). Смотрите пример ниже:

@Component(modules = {AppModule.class, MainActivityBinder.class})
@Singleton
interface AppComponent
{
   inject(MyApplication _)
}

@Subcomponent(modules = ActivityModule.class)
interface ActivitySubcomponent
{
   inject(MainActivity _)

   @Subcomponent.Builder
   interface Builder
   {
      @BindInstance
      Builder activity(Activity activity)

      ActivitySubcomponent build();
   }
}

Начальный шаг: у меня есть AppComponent это мой корневой компонент, который обеспечивает AppModule с синглетами (дооснащение, охттп и т. д.) в ActivitySubcomponent Я предоставляю ActivityModule с имеет зависимости, указанные для этого действия. Теперь подкомпонент должен быть добавлен в AppComponent, так что по-новому я создаю указанный модуль под названием MainActivityBinder, который имеет аннотации @Module.subcomponents с указанием на то, что связывает подкомпонент, но у меня есть первая проблема, что должно быть в теле этого модуля связывания?

@Module(subcomponents = ActivitySubcomponent.class)
public class MainActivityBinder
{
  //what body of this class should be ??
}

Я знаю, что идея заключается в том, что я могу связать субкомпонента или их строителя. Второй вопрос, когда связывать строителя, а когда связывать подкомпонент? Например мой ActivitySubcomponent требуемый контекст активности, поэтому я создаю конструктор, который предоставляет контекст для ActivityModule в этом случае будет лучше обеспечить в MainActivityBinder строитель? Третий вопрос, как вызвать компоновщик компонентов и как получить подкомпонент для компонента приложения? В стандартном субкомпонентном заводе я добавил AppComponent метод, который возвращает подкомпонент, и я могу определить параметры (например, дать контекст действия, указанный ниже)

@Component(modules = {AppModule.class})
@Singleton
interface AppComponent
{
   ActivitySubcomponents newActivitySubcomponents(Activity activity);

   inject(MyApplication _);
}

// in MainActivity
appComponent.newActivitySubcomponents(this).build().inject(this);

так достигнуть этого поведения в новом добавленном методе подкомпонента?

1 ответ

Решение
  1. Ваш модуль MainActivityBinder может быть пустым, и должен быть, если у вас нет ничего, чтобы связать с ним. Пустые (только аннотации) модули также полезны, когда вы используете только Module.includesНапример, когда вы хотите хранить список модулей в одном месте, а не дублировать его среди нескольких компонентов. subcomponents Атрибут в аннотации достаточен для того, чтобы Даггер понял, что вы пытаетесь сделать.

  2. Вы можете внедрить FooSubcomponent или Provider тогда и только тогда, когда у него нет методов @BindsInstance или инстанцируемых модулей (которые Dagger не может создать). Если все ваши модули являются интерфейсами, абстрактными классами или модулями, имеющими открытые конструкторы с нулевым аргументом, то вы можете напрямую внедрить подкомпонент. В противном случае вы должны вместо этого ввести свой компонент субкомпонента.

  3. Вы можете добраться до вашего компоновщика подкомпонентов, создав метод, который возвращает его в вашем AppComponent, так же, как вы можете для любой привязки, существующей в графе:

    @Component(modules = {AppModule.class, MainActivityBinder.class})
    @Singleton
    interface AppComponent {
      ActivitySubcomponent.Builder activitySubcomponentBuilder();
    
      inject(MyApplication _)
    }
    

    Вы также можете ввести его в объект по вашему выбору.

    @Inject ActivitySubcomponent.Builder activitySubComponentBuilder;
    activitySubComponentBuilder.activity(this).build().inject(this);
    
    // You can also inject a Provider<ActivitySubcomponent.Builder> if you want,
    // which is a good idea if you are injecting this directly into your Application.
    // Your Application will outlive your Activity, and may need to inject several
    // instances of the Activity across application lifetime.
    @Inject Provider<ActivitySubcomponent.Builder> activitySubComponentBuilderProvider;
    activitySubComponentBuilderProvider.get().activity(this).build().inject(this);
    

Несмотря на то, что, по-видимому, нет большого преимущества для внедрения построителя подкомпонентов, когда вы можете так же легко вызвать метод компонента (либо для возврата построителя, либо для возврата подкомпонента), есть несколько преимуществ для внедрения построителя:

  • Dagger не может определить, вызываете ли вы метод для компонента, поэтому он генерирует и компилирует код, даже если ваш подкомпонент не используется. Dagger может определить, пытались ли вы когда-нибудь внедрить конструктор, поэтому, если нет вложений подкомпонента / построителя и нет методов, Dagger пропустит генерацию кода для подкомпонента.
  • Если ваша кодовая база настолько велика, что вам нужно разделить ее на разные цели для компиляции, метод фабричного метода может поймать вас в некоторых циклах зависимостей, где компонент и модули вашего приложения зависят от всего, и вы можете получить доступ к своему подкомпоненту только из своего сам компонент. Благодаря инжектируемым компоновщикам субкомпонентов у вас есть больше вариантов того, как добраться до вашего субкомпонента или компоновщика.
Другие вопросы по тегам