使用 Dagger 2 的方法注入

Method injection using Dagger 2

我还没找到关于使用 Dagger 2 注入方法的好方法 explanation/example。有人能帮我理解一下吗?

示例:

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

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

更新:

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

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

我的 DinnerModule 是这样设置的:

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

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

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

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

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

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

@Inject 注释一个方法给 Dagger 指令在对象创建后立即执行此方法——在构造函数调用后立即执行。当你需要一个完全构造的对象时,这很有用。 this article.

中有方法注入的例子

你说得对,这个方法的参数将由 Dagger 提供,所以你不应该自己调用这个方法。

与您使用它的方式相比,Dagger 方法注入的一个根本区别是 Dagger 方法注入在构造或注入 DI 就绪对象时是just another way for Dagger to send in dependencies,这意味着 @Inject-annotated 方法应该由 Dagger 在构建时调用一次,而不是从您自己的代码中调用 。这使得您不太可能 @Inject-注释 makeDinnerfryDinner 或任何其他具有有意义的副作用或 return 值的方法。相反,将方法注入视为构造函数式注入的 post 构造机会。

(当然,您始终可以在方法级别练习一般依赖注入,将您的依赖项传递到方法调用中,这样方法本身就不必创建它们。但是,这不是 Dagger 的意思方法注入的定义,它无助于支持这种情况。)

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

在这种情况下,当您请求在 Chef 实例上注入时,Dagger 将看到 @Inject 注释的方法并使用 Dagger 图中的参数调用它。

不管是否有 Chef 是 Dagger 可构造的,这都适用:除非你有一个 @Inject 注释的构造函数或 @Provides 方法,否则你将无法直接从你的组件中获取 Chef,但你 可以在组件上创建一个void方法,它接收一个已经构建的Chef实例。该 Component 方法将使用字段和方法注入来为 Chef 提供他们可能需要的成分、Providers、Optionals 或 Lazys。有关详细信息,请参阅 @Component and MembersInjector 文档。

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

为什么要使用方法注入?虽然构造函数注入是更可取的,并且允许 class 的字段是 final,但请考虑反射创建对象的情况(例如 Android 中的活动、片段和视图,或可序列化对象)。字段注入(Dagger 填充 @Inject-注释字段)也可以工作,但在某些情况下,您可能不希望公开 @Inject-注释字段。在这些情况下,您可以通过在 @Inject 注释的方法上进行注入来解决构造函数约束。同样,虽然我没有尝试过,但您可以利用 class 层次结构来使用 @Inject 标记接口方法:这将确保无论您是否处于 DI 上下文中,都可以将某些依赖项传递给一个对象作为他们准备的一部分。