Android Dagger 2: Inject versus Provides

2020-06-01 01:20发布

问题:

I have a question regarding Android Dagger 2 und the usage of @Inject and @Provide annotations. Given are the following two simplified examples:

public class A {
  String msg;

  public A(String msg){
    this.msg = msg;
  }
}

public class B {
  public A a;

  public B(A a){
    this.a = a;
  }
}

@Module
public class AModule {
  @Provides
  A providesA(){
    return new A("blah");
  }

  @Provides
  B ProvidesB(A a)
  {
    return new B(a);
  }
}

The example is pretty straight forward, I have two methods in my AModule with @Provides annotations. Therefore, Dagger can create an object of B using an instance of A with the string blah.

My second example looks like this:

public class A {
  String msg;

  public A(String msg){
    this.msg = msg;
  }
}

public class B {
  public A a;

  @Inject
  public B(A a){
    this.a = a;
  }
}

@Module
public class AModule {
  @Provides
  A providesA(){
    return new A("blah");
  }
}

In this example, Dagger can create an instance of B because an object A can be created using AModule. The instance of B can be created because it's constructor uses the @Inject annotation.

So my question is: What's the difference between those two examples? Both seem to have the same semantics. Does the generated code differ and are there any pitfalls? Or is it just a matter or personal taste or best practices?

回答1:

They work similarly, and the @Inject style is preferred when you have such an easy choice like in your example. However, this isn't always the case:

  • If B, which consumes A, is not under your control and not DI-aware, you will have no way to add the @Inject annotation.
  • If B is an interface, you will need @Provides (or @Binds in newer Dagger versions) to identify which implementation to use.
  • If you choose not to use your Dagger object graph for every injected parameter, you can call the constructor manually whether it is marked @Inject or not. This might be the case if you want a specific instance or constant as a constructor parameter, but you can't or don't want to set up the binding for the whole object graph.
  • If you want your binding to return null sometimes or otherwise choose between implementations, that logic can live in a @Provides method.