java 使用 Dagger 2 的方法注入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39338870/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 04:17:32  来源:igfitidea点击:

Method injection using Dagger 2

javaandroiddependency-injectiondagger-2

提问by Vas

I haven't managed to find a good explanation/example on method injection using Dagger 2. Could someone please help me understand?

我还没有找到关于使用 Dagger 2 的方法注入的很好的解释/示例。有人可以帮我理解吗?

Example:

例子:

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

So if I annotate my method with @Inject, am I correct to assume that the arguments in the method signature will be injected with defined objects from the object graph? How can I use this method in my code then? It will still expect me to supply all the arguments, when I make the method call, which sort of defeats the purpose.

因此,如果我用 注释我的方法@Inject,我是否正确地假设方法签名中的参数将使用对象图中的已定义对象注入?那么如何在我的代码中使用这种方法呢?当我进行方法调用时,它仍然希望我提供所有参数,这有点违背了目的。

UPDATE:

更新:

So from what I understand the Dinner object will be available if I call DinnerComponent.dinner(), assuming my DinnerComponent is set up like this:

因此,据我所知,如果我调用 Dinner 对象将可用DinnerComponent.dinner(),假设我的 DinnerComponent 设置如下:

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

and my DinnerModule is set up like this:

我的 DinnerModule 设置如下:

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

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

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

What happens if I want my dinner fried? So let's introduce this method:

如果我想要我的晚餐油炸怎么办?那么我们来介绍一下这个方法:

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

How can I specify within the component which dinner is which?

我如何在组件中指定哪个晚餐是哪个?

回答by Jeff Bowman

One fundamental difference about method injection that differs from the way you seem to be using it is that method injection is just another way for Dagger to send in dependencieswhen constructing or injecting a DI-ready object, which means that @Inject-annotated methods are meant to be called by Dagger once on construction and not from within your own code. This makes it very very unlikely that you would @Inject-annotate makeDinner, fryDinner, or any other method that has meaningful side effects or return values. Instead, treat method injection as a post-facto opportunity for constructor-style injection.

方法注入的一个根本区别与您似乎使用它的方式不同的是,方法注入只是 Dagger在构造或注入 DI-ready 对象时发送依赖项的另一种方式,这意味着@Inject-annotated 方法是意味着在构建时由 Dagger 调用一次,而不是从您自己的代码中调用。这使得您不太可能使用@Inject-annotate makeDinnerfryDinner或任何其他具有有意义的副作用或返回值的方法。相反,将方法注入视为构造器样式注入的事后机会。

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();
  }
}

In this case, when you request injection on a Chef, Dagger will see the @Inject-annotated method and call it. Unless you have an @Inject-annotated constructor or @Provides method, you won't be able to get a Chef directly from your Component, but you couldcreate a voidmethod on the Component which receives a constructed Chefinstance and which uses field and method injection to provide that Chef with the ingredients (or ingredient Providers) they may need. (See the @Componentand MembersInjectordocs for details.)

在这种情况下,当您请求对 Chef 进行注入时,Dagger 将看到 @Inject-annotated 方法并调用它。除非您有@Inject-annotated 构造函数或@Provides 方法,否则您将无法直接从组件中获取 Chef,但您可以void在组件上创建一个方法,该方法接收构造的Chef实例并使用字段和方法注入为该厨师提供他们可能需要的原料(或原料供应商)。(有关详细信息,请参阅@ComponentMembersInjector文档。)

Note that in no case does Dinnerappear available on the object graph! Adding @Inject to a constructor tells Dagger that it can use that constructor to make the object available on the object graph, but adding @Inject to a method or field merely tells Dagger that as part of the injection process it should populate that field or call that method with the given dependencies. If you want to make a Dinner available on the object graph, you'll need to @Inject-annotate the Dinner constructor, or put a @Provides or @Binds method on a Module that you feed into the Component.

请注意,在任何情况下都不会Dinner出现在对象图上!将@Inject 添加到构造函数告诉 Dagger 它可以使用该构造函数使对象在对象图上可用,但是将 @Inject 添加到方法或字段只是告诉 Dagger 作为注入过程的一部分,它应该填充该字段或调用具有给定依赖项的该方法。如果您想让 Dinner 在对象图上可用,您需要对 Dinner 构造函数进行 @Inject-annotate,或者将 @Provides 或 @Binds 方法放在您提供给组件的模块上。

Why would you use this? Consider a case where objects are created reflectively (e.g. Activities, Fragments, and Views in Android, or Serializable objects), where you would prefer not to expose @Inject fields. In those cases, you could work around constructor constraints by having your injection happen on a field. Similarly, though I haven't tried this, you could take advantage of class hierarchy to mark an interface method with @Inject, ensuring that whether or not you're in a DI context you can pass certain dependencies to an object as part of their preparation.

你为什么要用这个?考虑这样一种情况,其中对象是反射式创建的(例如,Android 中的活动、片段和视图,或可序列化对象),在这种情况下,您不希望公开 @Inject 字段。在这些情况下,您可以通过在字段上进行注入来解决构造函数约束。类似地,虽然我还没有尝试过,但您可以利用类层次结构来标记带有 @Inject 的接口方法,确保无论您是否处于 DI 上下文中,您都可以将某些依赖项作为其一部分传递给对象准备。

回答by Egor Neliuba

Annotating a method with @Injectgives Dagger instructions to execute this method right after the object's creation — right after the constructor call. This is useful when you need a fully constructed object for something. There is an example of method injection in this article.

注释一个方法@Inject给 Dagger 指令以在对象创建后立即执行此方法 - 就在构造函数调用之后。当你需要一个完全构造的对象时,这很有用。这篇文章中有一个方法注入的例子。

You are right by saying that this method's parameters will be supplied by Dagger, that's why you are not supposed to call this method by yourself.

你说这个方法的参数将由 Dagger 提供是对的,这就是为什么你不应该自己调用这个方法。