Dagger 2.10 Android подкомпоненты и компоновщики

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

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

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

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

Подкомпонент, о котором идет речь, на самом деле относится к Фрагменту, а не к Деятельности, но я не уверен, что это должно иметь значение. Есть идеи о том, как это сделать?

2 ответа

Решение

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

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


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

Как вы могли бы сказать из AndroidInjection.inject(this) а также AndroidInjector.Factory.create(T instance)у вас мало возможностей для передачи деталей, относящихся к конкретным операциям или фрагментам, вашему построителю. Вместо этого идея состоит в том, что ваш субкомпонентный конструктор переопределяет 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(...));
}

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

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

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

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

со https://github.com/google/dagger/issues/615.

Другие вопросы по тегам