В Dagger аннотированный класс Inject также выступает в роли провайдера? - PullRequest
0 голосов
/ 22 мая 2018

Я новичок в Dagger (версия 2.16 для Android) и, основываясь на моих результатах, я понимаю, что для компонента должен быть поставщик (@Provides или @Binds), инкапсулированный в модуль (* 1003).*).Проходя через множество примеров, я вижу код, в котором есть некоторые объекты, которые не предлагаются ни в одном модуле, и их экземпляры не создаются с использованием new.

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

Вот код , демонстрирующий обе мои проблемы. RecipePresenter не предоставляется ни в одном модуле, но все еще RecipeActivity использует его.

Возможное объяснение, которое я мог бы придумать, заключается в том, что @Inject, в дополнение кзапрос зависимости также добавляет / вводит запрашивающий класс (RecipePresenter в связанном коде) в граф компонентов.Но если предположить, что есть несколько компонентов / подкомпонентов, к какому компоненту присоединяется класс, использующий конструктор @Inject? Если мое понимание правильное , почему действия и фрагменты должны вводить себя вручную в компоненте - не должны ли они быть автоматически введены, если они объявляют переменную, помеченную @Inject?

1 Ответ

0 голосов
/ 23 мая 2018

RecipePresenter имеет конструктор, аннотированный @Inject, что позволяет его предоставлять.Аннотация @Inject в поле recipePresenter в RecipeActivity не помогает, только конструктор, аннотированный @Inject.

class RecipePresenter @Inject constructor(
    private val useCase: RecipeUseCase,
    private val res: StringRetriever) :
    RecipeUseCase.Callback {

Из руководства пользователя Dagger:

Используйте @Inject, чтобы аннотировать конструктор, который Dagger должен использовать для создания экземпляров класса.Когда запрашивается новый экземпляр, Dagger получит требуемые значения параметров и вызовет этот конструктор.

Если класс с конструктором, аннотированным @Inject, также имеет определенный scope тогда привязка будет влиять только на компоненты с той же аннотацией области: например, класс @ActivityScope не будет доступен из компонента @Singleton.Если для класса не определена область действия, то привязка может появиться в любом и во всех компонентах, где это необходимо, и это нормально: реализация всегда одна и та же, определяемая самим конструктором.


@Inject имеет различные значения в зависимости от того, что он аннотирует:

  • Когда вы аннотируете поле с помощью @Inject, это означает, что система DI должна установить это поле на основе значений изсистема DI , когда вводит этот объект.
  • Когда вы аннотируете метод с помощью @Inject, это указывает, что система DI должна вызывать этот метод с параметрами, основанными на значениях из системы DI когда вводит этот объект.
  • Когда вы аннотируете конструктор с помощью @Inject, это указывает, что системе DI разрешено вызывать этот конструктор для создания этого объекта (который инициирует введение поля и метода выше).В этом смысле он действует как встроенный провайдер.

В частности, в Dagger методы @Provides имеют приоритет над конструкторами @Inject (если они оба существуют для одного и того же класса), и в отличие отв спецификации JSR-330 Dagger требуется аннотированный конструктор @Inject, даже если другие конструкторы отсутствуют.Из Руководства пользователя Dagger:

Если в вашем классе есть поля, аннотированные @Inject, но нет конструктора, аннотированного * 1054, Dagger вставит эти поля по запросу, но не будет создавать новые экземпляры.Добавьте конструктор без аргументов с аннотацией @Inject, чтобы указать, что Dagger может также создавать экземпляры.

Классы, в которых отсутствуют аннотации @Inject, не могут быть созданы Dagger.


Наконец, чтобы ответить на ваш вопрос о том, почему действия и фрагменты нужно вводить самим: Android разрешено рефлексивно создавать объекты Activity / Fragment / View без помощи или участия Кинжала. Это означает, что поле ничего не вызываети внедрение метода, описанное выше, до тех пор, пока вы не вызовете метод внедрения членов в компоненте , который инструктирует Dagger заполнить эти поля и вызвать эти методы.Следовательно, вы никогда не должны видеть аннотированный конструктор @Inject в подклассах Application, Activity, Service, Fragment, View, ContentProvider и BroadcastReceiver в Android: Android будет игнорировать аннотацию @Inject, так что вы могли бы также взять под контроль внедрениесамостоятельно, вручную или через dagger.android .

...