Кинжал не впрыскивает пустым методом - PullRequest
0 голосов
/ 29 августа 2018

У меня есть компонент приложения (содержит только синглеты), который доступен статическим методом App.getComponent();. Мой компонент содержит метод void inject(MainActivity activity), и он отлично работает. У меня тоже есть void inject(TaskRepo repo), но этот не работает. В TaskRepoImpl() я вызываю: App.getComponent().inject(this);, но это ничего не вводит. Я уверен, что я пометил публичных участников @Inject.

Инъекция такими методами, как TaskRepo repo = App.getComponent().taskRepo();, работает нормально. Так почему же Кинжал игнорирует этих членов?

1 Ответ

0 голосов
/ 30 августа 2018

Короче говоря, вам нужно, чтобы метод был void inject(TaskRepoImpl impl); Вы не можете просто принять TaskRepo. Ваш случай описан в документации по компонентам в разделе «Примечание о ковариации» .

Dagger - это среда времени компиляции: в время компиляции Dagger рассмотрит ваш Компонент и напишет реализации, основанные на методах вашего Компонента (и его модулей). Некоторыми из этих методов могут быть методы внедрения членов (та же ссылка, что и выше), которые представляют собой методы с одним аргументом, которые устанавливают @Inject поля и вызывают @Inject методы для экземпляра, который вы передаете. Обычно это void методы с именем inject, но они могут называться как угодно, и они также могут возвращать экземпляр, который они внедряют (для создания цепочки).

Хитрость в том, что Кинжал может ожидать только поля и методы определенного вами типа, а не его подклассы : если вы создаете метод внедрения членов void inject(Foo foo), то только поля и методы Foo считать, даже если у подкласса Foo есть методы, помеченные @Inject. Даже если ваш граф Даггера знает о Foo и Bar, он не будет знать о других подклассах Foo и не обязательно будет готов к их внедрению (потому что все это происходит во время компиляции). Это также не является проблемой для «методов обеспечения» (фабрики / получатели с нулевым аргументом в компонентах), поскольку, пока Dagger знает, как создать конкретный конкретный тип для привязки, он может внедрить этот конкретный тип и просто вернуть ссылку как его супертип или интерфейс.

Следовательно, переключение внедрения на фактический класс реализации устраняет эту проблему, поскольку Dagger может проверять класс реализации TaskRepoImpl во время компиляции и гарантировать, что он имеет привязки, которые TaskRepoImpl определяет в своем @Inject -аннотированном методы и поля.

@Component(modules = {...}) public interface YourComponent {
  /**
   * Only injects the fields and methods on TaskRepo, which might do
   * nothing--especially if TaskRepo is just an interface.
   */
  void inject(TaskRepo taskRepo);

  /**
   * Injects the fields and methods on TaskRepoImpl, TaskRepo, and
   * any other superclasses or interfaces.
   */
  void inject(TaskRepoImpl taskRepoImpl);

  /**
   * Gets a TaskRepo implementation. If you've bound TaskRepo to TaskRepoImpl,
   * Dagger _can_ inject all of TaskRepoImpl's fields, because it knows at
   * compile time that there's a TaskRepoImpl instance to inject.
   */
  TaskRepo taskRepo();
}

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

...