web-dev-qa-db-fra.com

Injection de méthode à l'aide de Dagger 2

Je n'ai pas réussi à trouver une bonne explication/exemple sur l'injection de méthode à l'aide de Dagger 2. Quelqu'un pourrait-il m'aider à comprendre?

Exemple:

@Inject
public Dinner makeDinner(Pasta pasta, Sauce sauce) {
    mPan.add(pasta);
    mPan.add(sauce);
    return mPan.cookDinner();
}

Donc, si j'annote ma méthode avec @Inject, Ai-je raison de supposer que les arguments dans la signature de la méthode seront injectés avec des objets définis à partir du graphe d'objets? Comment puis-je utiliser cette méthode dans mon code? Il s'attendra toujours à ce que je fournisse tous les arguments, lorsque je lance l'appel de méthode, ce qui en quelque sorte va à l'encontre du but.

MISE À JOUR:

Donc d'après ce que je comprends, l'objet Dinner sera disponible si j'appelle DinnerComponent.dinner(), en supposant que mon DinnerComponent est configuré comme ceci:

@Component(modules = DinnerModule.class)
public interface DinnerComponent {
    Dinner dinner();
}

et mon DinnerModule est configuré comme ceci:

@Module
public class DinnerModule {
    public DinnerModule() {}

    @Provides
    Pasta providePasta() { return new Pasta(); }

    @Provides
    Sauce provideSauce() { return new Sauce(); }
}

Que se passe-t-il si je veux que mon dîner soit frit? Présentons donc cette méthode:

@Inject
public Dinner makeDinner(Pasta pasta, Sauce sauce) {
    mPan.add(pasta);
    mPan.add(sauce);
    return mPan.fryDinner();
}

Comment puis-je spécifier dans le composant quel dîner est lequel?

33
Vas

Une différence fondamentale à propos de l'injection de méthode qui diffère de la façon dont vous semblez l'utiliser est que l'injection de méthode est juste une autre façon pour Dagger d'envoyer des dépendances lors de la construction ou injecter un objet prêt pour DI , ce qui signifie que @ Les méthodes annotées par injection sont censées être appelées par Dagger une fois lors de la construction et non depuis votre propre code . Cela rend très peu probable que vous @Inject- annoter makeDinner, fryDinner, ou toute autre méthode ayant des effets secondaires ou des valeurs de retour significatives. Au lieu de cela, traitez l'injection de méthode comme une opportunité post-facto pour une injection de style constructeur.

public class Chef {
  private Provider<Pasta> mPastaProvider;
  private Sauce mSauce;

  @Inject
  public void registerIngredients(     // can be named anything
      Provider<Pasta> pastaProvider,
      Sauce sauce) {                   // T and Provider<T> both work, of course
    mPastaProvider = pastaProvider;
    mSauce = sauce;
  }

  /* Non-@Inject */ public Dinner cookDinner() {
    mPan.add(mPastaProvider.get());
    mPan.add(mSauce);
    return mPan.cookDinner();
  }

  /* Non-@Inject */ public Dinner fryDinner() {
    mPan.add(mPastaProvider.get());
    mPan.add(mSauce);
    return mPan.fryDinner();
  }
}

Dans ce cas, lorsque vous demandez l'injection sur un Chef, Dagger verra la méthode annotée @ Inject et l'appellera. À moins d'avoir un constructeur @ Inject-annoté ou une méthode @Provides, vous ne pourrez pas obtenir un chef directement à partir de votre composant, mais vous pourriez créer une méthode void sur le composant qui reçoit une instance Chef construite et qui utilise l'injection de champ et de méthode pour fournir à ce chef les ingrédients (ou les fournisseurs d'ingrédients) dont il peut avoir besoin. (Voir les documents @ Component et MembersInjector pour plus de détails.)

Notez qu'en aucun cas Dinner n'apparaît disponible sur le graphe objet! L'ajout de @Inject à un constructeur indique à Dagger qu'il peut utiliser ce constructeur pour rendre l'objet disponible sur le graphique d'objet, mais l'ajout de @Inject à une méthode ou à un champ indique simplement à Dagger que dans le cadre du processus d'injection, il doit remplir ce champ ou appeler cette méthode avec les dépendances données. Si vous souhaitez rendre un dîner disponible sur le graphique d'objet, vous devrez @ Injecter-annoter le constructeur Dinner, ou mettre une méthode @Provides ou @Binds sur un module que vous introduisez dans le composant.

Pourquoi utiliseriez-vous cela? Prenons un cas où les objets sont créés de manière réfléchie (par exemple, les activités, les fragments et les vues dans Android ou les objets sérialisables), où vous préféreriez ne pas exposer les champs @Inject. Dans ces cas, vous pouvez contourner les contraintes du constructeur en effectuant votre injection sur un champ. De même, même si je n'ai pas essayé cela, vous pouvez profiter de la hiérarchie des classes pour marquer une méthode d'interface avec @Inject, en vous assurant que, que vous soyez ou non dans un contexte DI, vous pouvez transmettre certaines dépendances à un objet dans le cadre de leur préparation.

42
Jeff Bowman

Annoter une méthode avec @Inject donne des instructions à Dagger pour exécuter cette méthode juste après la création de l'objet - juste après l'appel du constructeur. Ceci est utile lorsque vous avez besoin d'un objet entièrement construit pour quelque chose. Il y a un exemple d'injection de méthode dans cet article .

Vous avez raison de dire que les paramètres de cette méthode seront fournis par Dagger, c'est pourquoi vous n'êtes pas censé appeler cette méthode par vous-même.

12
Egor Neliuba