Вопрос-ответ

How do I fix Dagger 2 error '... cannot be provided [...]'?

Как мне исправить ошибку Dagger 2 '... не может быть предоставлена [...]'?

Это канонический вопрос, потому что это распространенная ошибка с Dagger 2.


Если ваш вопрос был помечен как дублирующий пожалуйста, внимательно прочтите это сообщение и убедитесь, что понимаете, что означает эта ошибка и почему она возникла. Если этот пост не подходит для вас, обязательно укажите, где и как вы предоставляете упомянутые классы, и включите полное сообщение об ошибке в свой вопрос, подобный приведенному здесь.


Я пытался использовать зависимость с Dagger 2, но при попытке скомпилировать свой проект получаю следующую ошибку:


ошибка: com.пример.MyDependency не может быть предоставлена без конструктора @Inject или из метода с аннотацией @Provides .


com.пример.MyDependency предоставляется в
com.example .MyComponent.myDependency()


Что это значит и как я могу это исправить?

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

// this is the dependency I try to use
class MyDependency {}

@Component
interface MyComponent {
// I want to make it accessible to be used with my component
MyDependency myDependency();
}
Переведено автоматически
Ответ 1

tl; dr Вы забыли либо добавить @Inject в свой конструктор, чтобы Dagger мог использовать внедрение конструктора для предоставления объекта, либо вам нужен какой-то метод в одном из ваших модулей, который создает или привязывает объект.


Что происходит?

Внимательно посмотрите на сообщение об ошибке: в нем говорится, что вы пытаетесь запросить зависимость, но у Dagger нет способа предоставить или создать ее. Он просто не знает, как это сделать, потому что это не может быть предоставлено без конструктора @Inject или из метода с аннотацией @Provides.

При внимательном рассмотрении сообщения об ошибке отображается класс (a), который вы пытаетесь предоставить, и компонент (b), которому это необходимо.


com.пример.MyDependency (a) предоставляется в
com.example .MyComponent.myDependency () (b)


Вы должны убедиться, что (b) можно создать или предоставить (a), чтобы устранить вашу проблему.

Это выглядит немного сложнее, если вы попытались внедрить свою зависимость где—то еще, но вы все равно можете видеть полный стек событий - в этом случае при внедрении конструктора отсутствует зависимость. Класс (a), который вы пытаетесь предоставить, и местоположение (b), куда Dagger пытался его внедрить. В нем также сообщается, где был создан этот зависимый класс (c) и снова компонент (d), которому не удалось предоставить (a).


com.пример.MyDependency не может быть предоставлена без конструктора @Inject или из метода с аннотацией @Provides .
com.пример.MyDependency (a) вводится в
com.example.DependentClass. (зависимость) (b)
com.пример.DependentClass предоставляется по адресу (c)
com.пример.MyComponent.myDependency() (d)


То же самое применимо и здесь: убедитесь, что (d) знает, как предоставить (a), и все готово.

Как мне это исправить?

Посмотрите на ошибку, как показано выше. Убедитесь, что вы понимаете, где она произошла и что вы пытаетесь внедрить. Затем сообщите Dagger, как предоставить ваш объект.

конструктор @Inject

Как указано в ошибке, вы пытаетесь использовать MyDependency но MyComponent не знаете, как это сделать. Если мы посмотрим на пример, становится ясно, почему:

class MyDependency {}

У класса нет @Inject аннотированного конструктора! И в компоненте нет другого модуля, поэтому Dagger ничего не может сделать.

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

class MyDependency {
@Inject
MyDependency() { /**/ }
}

Это все, что вам нужно сделать, когда вы можете использовать внедрение конструктора.

из метода @Provides-annotated

В сообщении об ошибке указан второй вариант, который позволяет вам предоставить объект, если вы не хотите — или не можете — использовать внедрение конструктора. Вы также можете добавить @Provides аннотированный метод в модуль и добавить этот модуль в свой компонент.

@Module
class MyModule {
@Provides
MyDependency provideMyDependency() {
return new MyDependency();
}
}

@Component(modules = MyModule.class)
interface MyComponent {
MyDependency myDependency();
}

Таким образом, Dagger может использовать ваш модуль для создания и предоставления вашей зависимости. Это немного более шаблонно, чем использование внедрения конструктора, но вам придется использовать модули для всего, что требует дальнейшей настройки или у чего нет аннотированного конструктора, например, сторонних библиотек, таких как Retrofit, OkHttp или Gson.


Существуют также другие способы предоставления зависимости от компонента. A @SubComponent имеет доступ к своим родительским зависимостям, а зависимость от компонента может предоставлять некоторые из своих зависимостей зависимым компонентам. Но в какой-то момент все, что предоставляет Dagger, должно иметь @Inject конструктор или модуль, предоставляющий его.

Но я добавил MyDependency!

Обратите пристальное внимание на детали. Вероятно, вы используете интерфейс, когда предоставляете только реализацию, или пытаетесь использовать родительский класс, когда Dagger знает только о подклассе.
Возможно, вы добавили пользовательский @Qualifier или использовали @Named("typeA") с ним. Для Dagger это совершенно другой объект! Дважды проверьте, действительно ли вы предоставляете и запрашиваете одну и ту же зависимость.

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

Что, если я хочу предоставить реализацию для своего интерфейса?

Простой пример, подобный следующему, показывает, как один класс расширяет другой:

class MyDependency extends MyBaseDependency {
@Inject MyDependency() { super(); }
}

Это проинформирует Dagger о MyDependency, но не о MyBaseDependency.

Если у вас есть один класс, реализующий интерфейс или расширяющий суперкласс, вы должны объявить это. Если вы предоставляете MyDependency это не означает, что Dagger может предоставить MyBaseDependency. Вы можете использовать @Binds, чтобы сообщить Dagger о вашей реализации и предоставить ее, когда требуется суперкласс.

@Module
interface MyModule {
@Binds
MyBaseDependency provideMyBaseDependency(MyDependency implementation);
}
java