Ошибка Dagger 2: зависимость "не может быть предоставлена без конструктора @Inject", в то время как она фактически аннотирована с помощью @Inject
я начал использовать Dagger 2 и столкнулся со странной проблемой, которая выглядит как ошибка для меня.
у меня есть 3 модуля, которые состоят из одного подкомпонента, который, в свою очередь, расширяет/плюсы компонента более высокого уровня.
подкомпонент довольно прост: просто комбинация модулей и одна точка впрыска:
@Singleton
@Subcomponent(
modules = {
NavigationDrawerModule.class,
NavigationListModule.class,
SwitcherModule.class
}
)
public interface NavigationDrawerComponent {
NavigationDrawerFragment inject(NavigationDrawerFragment object);
}
первые модули выглядят так - он предоставляет общие зависимости на уровне фрагментов:
@Module
public class NavigationDrawerModule {
private final Activity activity;
private final View rootView;
private final LoaderManager loaderManager;
public NavigationDrawerModule(Activity activity, View rootView, LoaderManager loaderManager) {
this.activity = activity;
this.rootView = rootView;
this.loaderManager = loaderManager;
}
@Provides @Singleton EventBus provideLocalBus() {
return EventBus.builder().build();
}
@Provides @Singleton View provideViewRoot() {
return rootView;
}
@Provides @Singleton LoaderManager provideLoaderManager() {
return loaderManager;
}
@Provides @Singleton Context provideContext() {
return activity;
}
}
второй модуль выглядит это обеспечивает контроллере ведущий/и их зависимостей для подмножества UI на экране:
@Module
public class SwitcherModule {
@Provides SwitchController provideSwitcherController(SwitchControllerImpl impl) {
return impl;
}
@Provides SwitcherView provideSwitcherView(SwitcherViewImpl impl) {
return impl;
}
}
третий модуль - другой ведущий/контроллер для подмножества интерфейса:
@Module
public class NavigationListModule {
@Provides @Singleton NavigationListController provideNavigationListController(NavigationListControllerImpl impl) {
return impl;
}
@Provides @Singleton NavigationListView provideNavigationListView(NavigationListViewImpl impl) {
return impl;
}
}
соответствующая часть фрагмента, который вводится:
@Inject SwitchController identitySwitchController;
@Inject SwitcherView identitySwitcherView;
@Inject NavigationListController navigationListController;
@Inject NavigationListView navigationListView;
NavigationListControllerImpl
реализует следующий конструктор:
@Inject
public NavigationListControllerImpl(Context ctx, EventBus bus) {
this.ctx = ctx;
this.bus = bus;
}
ошибка, которую я получаю от компилятора Dagger 2, Следующая:
error: ...sidenavigation.navigationlist.NavigationListControllerImpl cannot be provided without an @Inject constructor or from an @Provides-annotated method.
...sidenavigation.NavigationDrawerFragment.navigationListController
[injected field of type: ...sidenavigation.navigationlist.NavigationListController navigationListController]
...sidenavigation.navigationlist.NavigationListModule.provideNavigationListController(...sidenavigation.navigationlist.NavigationListControllerImpl impl)
[parameter: ...sidenavigation.navigationlist.NavigationListControllerImpl impl]
ошибка жалуется на отсутствие @Inject-аннотированный конструктор, но он существует! Если я заменю неявное создание экземпляра NavigationListControllerImpl (передача через @Provides
-параметр метода) с явным (с new
), dagger начинает жаловаться на ту же ошибку, но теперь для объекта presenter, который является второй записью в том же модуле, и так далее.
вся эта ситуация выглядит очень странно, и я хотел бы услышать некоторые материалы от более опытных пользователей Dagger 2 (и разработчиков?).
спасибо заранее!
6 ответов
я получил эту же ошибку, потому что забыл предоставить объекты, предоставляемые модулями в Родительском компоненте, другим компонентам, которые зависят от него.
пример родительского компонента:
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
AppPref exposeAppPref(); /* my issue was caused by forgot this line,
the method name doesn't matter, what matters is the object type AppPref provided in the AppModule
that you want it to be available in the component that declares this component as one of its dependencies*/
}
пример компонента, который делает вышеуказанный компонент зависимостью
@UserScope
@Component (dependencies = {AppComponent.class})
public interface ActivityComponent {
void inject(MainActivity activity);
}
обновление:
AppModule:
...
@Provides
@Singleton
AppPref provideAppPref() {
return appPref;
}
...
кажется, я понял, что случилось с моей установкой Dagger 2. Невозможно использовать одну и ту же область в компонентах и подкомпонентах. Это требуются чтобы определить новую область для подкомпонентов. В моем случае я закончил создание @ Screen scope для меня подкомпонента.
Я бы сказал, что это небольшой, но очень раздражающий дефект в Dagger 2. По-видимому, dagger-компилятор сообщает приятную и понятную ошибку об одних и тех же областях в Родительском компоненте и дочернем компонент, если дочерний компонент расширен родительским компонентом в качестве зависимости. Но компилятор сообщает о полностью вводящей в заблуждение ошибке, если родительский компонент и дочерний подкомпонент имеют одинаковую область.
спасибо, @lukas, за подсказку здесь https://stackoverflow.com/a/30383088/808313 это привело к решению проблемы.
GlobalComponent и подкомпонент NavigationDrawerComponent должны иметь разные области. Используйте @Singleton для вашего GlobalComponent и некоторую другую область для подкомпонента.
в противном случае, если вы применяете ту же область к GlobalComponent и к субкомпоненту, вы должны объявить модули вашего субкомпонента в вашем глобальном компоненте:
@Component(
// modules from subcomponent must be declared here also
modules = {NavigationListModule.class,
SwitcherModule.class,
NavigationDrawerModule.class,
...}
)
@Singleton
public interface GlobalComponent {
NavigationDrawerComponent plus(NavigationDrawerModule module);
}
для вашего варианта использования вы также можете использовать зависимости компонентов. Например:
@Component(
dependencies = GlobalComponent.class,
modules = {NavigationListModule.class,
SwitcherModule.class,
NavigationDrawerModule.class}
)
@YourOtherDaggerScope // @Singleton scope won't work here, it must be a different scope
public interface NavigationDrawerComponent extends GlobalComponent { // extend the parent component if you wish to get access to parent dependencies
NavigationDrawerFragment inject(NavigationDrawerFragment object);
}
пришел по этому вопросу сегодня тоже. Для меня возникла проблема с обработкой аннотаций (на Android Studio 2.2 с gradle 2.икс.)
вместо ~~АПТ~~ я annotationProcessor Я использовал
annotationProcessor 'com.google.dagger:dagger-compiler:2.6'
и теперь он работает.
столкнулся с той же проблемой при попытке создать Подкомпоненты, но, похоже, она исправлена в Dagger 2.0.1.
кажется, это тот же самый кинжал ошибок для многих ошибок. В моем случае моя целевая инъекция ожидала конкретный класс (Presenter), где в качестве модуля, предоставляющего presenter, возвращался только интерфейс (DemoContract.Ведущий)
изменилась с
@Inject
public Presenter mDemoPresenter;
to
@Inject
public DemoContract.Presenter mDemoPresenter;
и модуль, который предоставляет presenter выглядит так:
@Module
public class DiDemoPresenterModule {
private final DemoContract.View mView;
DiDemoPresenterModule(MainActivity mView) {
this.mView = mView;
}
@Provides
public DemoContract.Presenter providesDemoPresenter(Repository repository) {
return new DemoPresenter(repository, mView);
}
}