Подтвердить что ты не робот

Dagger 2.10 Подкомпоненты и разработчики Android

Используя новые (в 2.10) классы кинжала.андроида, я пытаюсь внедрить вещи, используя подкомпонент, который зависит от других модулей, и, следовательно, имеет Builder с сеттерами для этих модулей. Документация на https://google.github.io/dagger/android.html описывает это, но неясно, как на самом деле писать и/или вызывать эти сеттеры.

Цитата из приведенной выше ссылки:

AndroidInjection.inject() получает DispatchingAndroidInjector из приложения и передает вашу активность для ввода (Activity). DispatchingAndroidInjector ищет AndroidInjector.Factory для вашего класса активности (который является YourActivitySubcomponent.Builder), создает AndroidInjector (который является YourActivitySubcomponent) и передает вашу активность для ввода (YourActivity).

Мне кажется, что для того, чтобы иметь возможность звонить сеттерам для Builder, мне нужно где-то попасть и обеспечить, чтобы Builder имел все необходимые данные? Проблема, которую я вижу, заключается в том, что во время выполнения я получаю IllegalStateException: MODULE must be set, когда сгенерированный конструктор для моего подкомпонента вызывается AndroidInjector.

Подкомпонент, о котором идет речь, на самом деле относится к фрагменту, а не к активности, но я не уверен, что это важно. Любые идеи о том, как это сделать?

4b9b3361

Ответ 1

Короче говоря, вы должны переопределить вызов seedInstance в Builder (который является абстрактным классом, а не интерфейс) для предоставления других необходимых вам модулей.

edit: Прежде чем вы это сделаете, проверьте и убедитесь, что вам действительно нужно передать этот модуль. Поскольку Дэймон добавил в отдельном ответе, если вы создаете определенный модуль для своего класса Android, вы можете полагаться на автоматическую инъекцию этого класса, чтобы вытащить конфигурацию или экземпляр из графика в этот момент. Поощрите его подход, если проще просто исключить параметры конструктора из вашего модуля, что также может обеспечить лучшую производительность, поскольку они избегают ненужных экземпляров и вызовов виртуальных методов.


Во-первых, кинжал.андроид за 30 секунд: Вместо того, чтобы иметь информацию о его родительской активности или фрагменте, Activity (или Fragment) вызывает AndroidInjection.inject(this), который проверяет приложение для HasActivityInjector (или родительские фрагменты, активность и приложение для HasFragmentInjector). Идея заключается в том, что вы вносите привязку к создаваемому многосвязью Map<Class, AndroidInjector.Factory>, где созданные привязки почти всегда являются сборщиками подкомпонентов, которые вы пишете, которые строят объекты-специфические подкомпоненты.

Как вы могли бы сказать из AndroidInjection.inject(this) и AndroidInjector.Factory.create(T instance), у вас не будет большой возможности передать подробные сведения о конкретном конкретном конкретном или фрагменте вашему Builder. Вместо этого идея заключается в том, что ваш субкомпонентный строитель переопределяет реализацию seedInstance. Как в документах для seedInstance:

Предоставляет instance для использования в графе привязки построенного AndroidInjector. По умолчанию это используется как метод BindsInstance, но он может быть переопределен для предоставления любых модулей, которым нужна ссылка на активность.

Это должен быть тот же самый экземпляр, который будет передан inject(Object).

Это выглядит примерно так:

@Subcomponent(modules = {OneModule.class, TwoModule.class})
public interface YourActivitySubcomponent extends AndroidInjector<YourActivity> {

  // inject(YourActivity) is inherited from AndroidInjector<YourActivity>

  @Builder
  public abstract class Builder extends AndroidInjector.Builder<YourActivity> {
    // Here are your required module builders:
    abstract Builder oneModule(OneModule module);
    abstract Builder twoModule(TwoModule module);

    // By overriding seedInstance, you don't let Dagger provide its
    // normal @BindsInstance implementation, but you can supply the
    // instance to modules or call your own BindsInstance:
    @Override public void seedInstance(YourActivity activity) {
      oneModule(new OneModule(activity));
      twoModule(new TwoModule(activity.getTwoModuleParameter()));
    }
  }
}

Предполагается, что вам нужно ждать экземпляра activity для модулей. Если нет, то у вас также есть возможность вызвать их при привязке подкомпонента:

@Provides @IntoMap @ActivityKey(YourActivity.class)
AndroidInjector.Factory bindInjector(YourActivitySubcomponent.Builder builder) {
  return builder
      .oneModule(new OneModule(...))
      .twoModule(new TwoModule(...));
}

... но если вы можете это сделать, тогда вы можете более легко позаботиться об этих привязках, переопределив эти модули, внедряя конструктор с нулевым аргументом, который может предоставить параметры конструктора модуля, и позволяя кинжалу создавать такие объекты для любых модулей с общедоступными конструкторами с нулевым аргументом.

Ответ 2

который работает, но это не нужно. метод seedInstance предоставляет экземпляр активности в графе, поэтому вы можете иметь MyActivityModule без состояния и просто запрашивать MyActivity в методах @Provides.

class MyActivityModule {
  @Provides
  static SomethingDerivedFromMyActivity providesMethod(MyActivity myActivity) {
    return myActivity.somethingDerived();
  }
}

Выполнение этого сохраняет экземпляр модуля и позволяет сгенерированным фабрикам быть более компактными.

из https://github.com/google/dagger/issues/615.