3 votes

Pourquoi Dagger 2 me force-t-il à utiliser @Provides au lieu de @Binds ?

Je me penche actuellement sur Dagger 2 (Java) et j'ai rencontré un problème dès le départ. Malheureusement, je n'ai pas été en mesure de trouver quelque chose à ce sujet dans la documentation de Dagger 2 ou sur Stackoverflow, donc si vous connaissez des ressources, je vous en serais vraiment reconnaissant.

J'ai préparé un exemple minimal dans ce référentiel pour expliquer mon problème : https://github.com/stackoverflow-samples/dagger2-dependency-cycle

Donc on a un Application la classe qui doit être construite

public class Application {

    @Inject
    public Application(SomeDependency one) {

    }

    public static void main(String[] args) {
        DaggerApplicationComponent.create().build();
    }
}

... avec une dépendance fictive

public class SomeDependency {

    @Inject
    public SomeDependency() {

    }
}

Et bien sûr les classes/interfaces de Dagger ... ... une interface de composant :

@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
    Application build();
}

.. et un module :

@Module
abstract class ApplicationModule {
    @Provides
    static SomeDependency provideDepdendencyOne() {
        return new SomeDependency();
    }
}

Ce que je ne comprends pas, c'est pourquoi Dagger m'oblige à m'enregistrer. SomeDepdendency con @Provides et ne permet pas de l'enregistrer via l'annotation @Binds :

@Binds 
abstract SomeDependency bindDepdendencyOne(SomeDependency one);

Chaque fois que je change le code de @Provides a @Binds il me donne les erreurs suivantes :

[Dagger/DependencyCycle] Found a dependency cycle:
      io.github.codejanovic.dagger2.example.SomeDependency is injected at
          io.github.codejanovic.dagger2.example.ApplicationModule.bindDepdendencyOne(one)
      io.github.codejanovic.dagger2.example.SomeDependency is injected at
          io.github.codejanovic.dagger2.example.Application(one)
      io.github.codejanovic.dagger2.example.Application is provided at
          io.github.codejanovic.dagger2.example.ApplicationComponent.build()

Ne pas être capable de @Bind une mise en œuvre n'a absolument aucun sens pour moi. Que dois-je superviser ?

Merci d'avance.

6voto

David Medenjak Points 4553

Vous avez tort de penser que vous avez besoin @Binds ou @Provides en premier lieu. Vous pouvez et devriez utiliser l'injection de constructeur - pas le modèle, mais le Dagger génère le code pour moi genre.

Vous avez déjà le constructeur annoté avec @Inject Ainsi, Dagger connaît la classe et sait comment la créer. Il n'y a rien d'autre à faire.

public class SomeDependency {

    @Inject
    public SomeDependency() {

    }
}

Vous n'avez pas besoin de @Provides non @Binds pas même un @Module pour votre cas d'utilisation simple. Votre exemple devrait fonctionner dès le départ, puisque les deux constructeurs sont annotés avec le symbole @Inject .

@Component
public interface ApplicationComponent {
    Application build();
}

Si vous devez spécifier une portée, vous pouvez l'ajouter à la classe.


@Provides doit être utilisé pour le code pour lequel vous ne pouvez pas utiliser l'injection de constructeur, ou qui nécessite une configuration supplémentaire. Bien sûr, vous pouvez créer tous les objets manuellement (comme vous le faites dans votre exemple), mais cela n'a aucun avantage réel et ne fera que produire beaucoup de texte passe-partout qui peut être évité.

@Binds doit être utilisé avec les implémentations que vous devez lier à une interface. Idéalement, vous utiliserez l'injection de constructeur pour l'implémentation également, mais vous pouvez aussi l'ajouter au constructeur de composants ( @BindsInstance ) ou le créer dans un @Provides méthode annotée.

@Binds MyInterface bindMyImplementation(MyImplementation implementation);

1voto

Zhuinden Points 3074

Si votre classe est marquée d'un @Inject constructeur :

public class SomeDependency {

    @Inject // <----
    public SomeDependency() {

    }
}

Alors vous avez besoin @Binds (o @Provides ) uniquement si vous devez le "lier" en tant qu'implémentation d'une interface, ou au moins un type différent de son type concret.

De plus, si votre objet a un @Inject vous n'aurez pas besoin de l'instancier dans le module, car Dagger sait déjà comment l'instancier.

Donc pour corriger votre code, tout ce que vous devez faire est :

// @Module
// abstract class ApplicationModule {
//     @Provides
//     static SomeDependency provideDepdendencyOne() {
//         return new SomeDependency();
//     }
// }

Résolu.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X