Короче говоря, вам нужно, чтобы метод был 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
и избегая частично построенных (созданных, но не внедренных) экземпляров. Я рекомендую использовать конструктор инъекций, где это возможно, и настоятельно рекомендуем использовать , используя инжекцию полей и конструктор отдельно для одного и того же типа. (Вы, вероятно, делаете это не для того, чтобы отладить свое дело, но я оставляю записку здесь и для будущих читателей.)