Могу ли я использовать инъекцию с помощью Dagger?

С помощью Google Guice или Gin я могу указать параметр, который не контролируется структурой внедрения зависимостей:

class SomeEditor {


  @Inject
  public SomeEditor(SomeClassA a, @Assisted("stage") SomeClassB b) {
  }

}

Вспомогательный параметр stage указывается в то время, когда экземпляр SomeEditor создано.

Экземпляр SomeClassA берется из графа объектов, а экземпляр SomeClassB берется у вызывающей стороны во время выполнения.

Есть ли подобный способ сделать это в Dagger?

1 ответ

Решение

Поскольку фабрики являются отдельным типом шаблонной платформы для оптимизации ( см. Обсуждение списка рассылки здесь), Даггер оставляет это для родственного проекта, AutoFactory. Это обеспечивает функциональность " вспомогательной инъекции", которую Guice предлагает через FactoryModuleBuilder, но с некоторыми дополнительными преимуществами:

  • Вы можете продолжать использовать AutoFactory с Guice или Dagger или любым другим фреймворком внедрения зависимостей JSR-330, так что вы можете продолжать использовать AutoFactory, даже если вы переключаетесь между ними.
  • Поскольку AutoFactory генерирует код, вам не нужно писать интерфейс для представления конструктора: AutoFactory напишет совершенно новый тип для компиляции. (Вы также можете указать интерфейс для реализации, если хотите, или если вы мигрируете из Guice.)
  • Поскольку проверка всех типов происходит во время компиляции, она генерирует простую старую Java, которая не имеет медлительности из-за отражения и которая хорошо работает с отладчиками и оптимизаторами. Это делает библиотеку Auto особенно полезной для разработки под Android.

Пример, извлеченный из README AutoFactory, который будет производить SomeClassFactory с providedDepA в @Injectаннотированный конструктор и depB в create метод:

@AutoFactory
final class SomeClass {
  private final String providedDepA;
  private final String depB;

  SomeClass(@Provided @AQualifier String providedDepA, String depB) {
    this.providedDepA = providedDepA;
    this.depB = depB;
  }

  // …
}

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


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

Первое, что вам нужно, это зависимости:

compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0'

Тогда вот как это может выглядеть:

class ImageDownloader @AssistedInject constructor(
  private val httpClient: HttpClient,
  private val executorService: ExecutorService,
  @Assisted private val imageUrl: URL,
  @Assisted private val callback: ImageCallback
) {

  @AssistedInject.Factory
  interface Factory {
    fun create(imageUrl: URL, callback: ImageCallback): ImageDownloader
  }
}

Во-первых, вместо того, чтобы аннотировать конструктор @Inject мы аннотируем это @AssistedInject, Затем мы аннотируем параметры, которые должны пройти фабрику, что противоположно тому, что ожидает AutoFactory. Наконец, нам нужен внутренний фабричный интерфейс с комментариями @AssistedInject.Factory у него есть единственный метод, который получает вспомогательные параметры и возвращает интересующий нас экземпляр.

К сожалению, у нас все еще есть дополнительный шаг:

@AssistedModule
@Module(includes = [AssistedInject_AssistedInjectModule::class])
interface AssistedInjectModule

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

При этом вы можете в основном внедрить фабрику и запросить свой объект, как обычно.

Да, пожалуйста, проверьте этот квадратный проект: https://github.com/square/AssistedInject

В настоящее время это не в 1.0 еще для цели. Они ждут, пока Dagger представит общедоступный API для регистрации сгенерированных Module классы автоматически - смотрите эту проблему. При этом вам не придется ссылаться на них в коде Dagger, как в этом примере из README:

@AssistedModule
@Module(includes = AssistedInject_PresenterModule.class)
abstract class PresenterModule {}
Другие вопросы по тегам