¿Cómo soluciono el error de Dagger 2 '... no se puede proporcionar [...]'?

Resuelto David Medenjak asked hace 7 años • 1 respuestas

Esta es una pregunta canónica porque es un error común con Dagger 2.

Si su pregunta fue marcada como duplicada, lea esta publicación detenidamente y asegúrese de comprender qué significa este error y por qué ocurrió. Si esta publicación no funciona para usted, asegúrese de incluir dónde y cómo brinda las clases mencionadas e incluya el mensaje de error completo en su pregunta como la que se muestra aquí.

Intenté usar una dependencia con Dagger 2, pero recibo el siguiente error cuando intento compilar mi proyecto:

error: com.ejemplo. MyDependency no se puede proporcionar sin un constructor @Inject o desde un método anotado por @Provides.

com.ejemplo. MyDependency se proporciona en
com.example.MyComponent.myDependency()

¿Qué significa esto y cómo puedo solucionarlo?

Tengo un componente y traté de proporcionar una dependencia. Mi configuración básica se ve así:

// 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();
}
David Medenjak avatar Jul 05 '17 01:07 David Medenjak
Aceptado

tl;dr Olvidó agregar un an @Injecta su constructor para que Dagger pueda usar Constructor injection para proporcionar el objeto, o necesita algún método en uno de sus módulos que cree o vincule el objeto.


¿Qué está sucediendo?

Mire bien el mensaje de error: Indica que intenta solicitar una dependencia pero Dagger no tiene forma de proporcionarla o crearla . Simplemente no sabe cómo hacerlo, porque no se puede proporcionar sin un constructor @Inject o desde un método anotado @Provides.

Una mirada detenida al mensaje de error muestra la clase (a) que está intentando proporcionar y el componente (b) que lo necesita.

com.example.MyDependency (a) se proporciona en
com.example.MyComponent.myDependency() (b)

Debe asegurarse de que (b) pueda crear o proporcionar (a) para solucionar su problema.

Parece un poco más complejo si intentaste inyectar tu dependencia en otro lugar, pero aún puedes ver la pila completa de eventos; en este caso, a la inyección del constructor le falta una dependencia. La clase (a) que está intentando proporcionar y la ubicación (b) donde Dagger intentó inyectarla. También le indica dónde se creó esa clase dependiente (c) y nuevamente el componente (d) que falló al proporcionar (a) .

com.example.MyDependency no se puede proporcionar sin un constructor @Inject o desde un método anotado @Provides.
com.example.MyDependency (a) se inyecta en
com.example.DependentClass.(dependencia) (b)
com.example.DependentClass se proporciona en (c)
com.example.MyComponent.myDependency() (d)

Lo mismo se aplica aquí: asegúrese de que (d) sepa cómo proporcionar (a) y estará listo.

¿Cómo puedo solucionar esto?

Eche un vistazo al error que se muestra arriba. Asegúrese de comprender dónde ocurrió y qué está intentando inyectar. Luego dile a Dagger cómo proporcionar tu objeto.

un constructor @Inject

Como indica el error, intentas usarlo MyDependencypero MyComponentno sabes cómo hacerlo. Si echamos un vistazo al ejemplo, queda claro por qué:

class MyDependency {}

¡ La clase no tiene @Injectconstructor anotado ! Y no hay ningún otro módulo en el componente, por lo que Dagger no puede hacer nada.

Si desea utilizar la inyección de constructor, puede simplemente agregar un @Injectconstructor anotado y listo. Dagger verá este constructor y sabrá cómo crear su clase.

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

Eso es todo lo que tienes que hacer cuando puedas utilizar la inyección de constructor.

de un método anotado por @Provides

El mensaje de error indica una segunda opción, que le permite proporcionar un objeto si no desea (o no puede) utilizar la inyección del constructor. También puede agregar un @Providesmétodo anotado a un módulo y agregar este módulo a su componente.

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

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

De esta manera, Dagger puede usar su módulo para crear y proporcionar su dependencia. Es un poco más repetitivo que usar Constructor Inyección, pero tendrás que usar Módulos para todo lo que necesite mayor configuración o que no tenga un constructor anotado, por ejemplo, bibliotecas de terceros como Retrofit, OkHttp o Gson.


También hay otras formas de proporcionar una dependencia de un componente. A @SubComponenttiene acceso a sus dependencias principales y una dependencia de componente puede exponer algunas de sus dependencias a sus componentes dependientes. Pero en algún momento, todo lo que proporciona Dagger debe tener un @Injectconstructor o un módulo que lo proporcione.

¡Pero agregué MyDependency!

Presta mucha atención a los detalles. Probablemente esté utilizando una interfaz cuando solo proporciona la implementación, o intente usar una clase principal cuando Dagger solo conoce la subclase.
Tal vez agregaste una costumbre @Qualifiero usaste @Named("typeA")con ella. ¡Para Dagger este es un objeto completamente diferente! Verifique que realmente proporcione y solicite la misma dependencia.

Lea el error y asegúrese de tener un @Injectconstructor anotado, un módulo que tenga un @Providesmétodo que proporcione ese tipo o un componente principal que lo haga.

¿Qué pasa si quiero proporcionar una implementación para mi interfaz?

Un ejemplo simple como el siguiente muestra cómo una clase extiende a otra:

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

Esto informará a Dagger sobre MyDependency, pero no sobre MyBaseDependency.

Si tiene una clase que implementa una interfaz o extiende una superclase, debe declararla. Si usted proporciona MyDependencyesto no significa que Dagger pueda proporcionarlo MyBaseDependency. Puede utilizarlo @Bindspara informarle a Dagger sobre su implementación y proporcionarla cuando se requiera la superclase.

@Module
interface MyModule {
    @Binds
    MyBaseDependency provideMyBaseDependency(MyDependency implementation);
}
David Medenjak avatar Jul 04 '2017 18:07 David Medenjak