Могу ли я использовать инъекцию с помощью 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 {}