Dagger 2 injecting parameters of constructor

2019-01-16 14:44发布

问题:

I saw the following example on the Dagger 2 website:

class Thermosiphon implements Pump {
  private final Heater heater;

  @Inject
  Thermosiphon(Heater heater) {
    this.heater = heater;
  }

  ...
}

and the documentation:

When a new instance is requested, Dagger will obtain the required parameters values and invoke this constructor.

When I write a Module to provide a Thermosiphon like

@Module
public class ThermosiphonModule {

    @Provides
    @Singleton
    Thermosiphon provideThermosiphon() {
        return new Thermosiphon(???);
    }

}

the Thermosiphon constructor still requires a Heater as an argument, rendering the whole 'automatic injection of constructor dependencies' useless.

I tried

return new Thermosiphon(null); 

and

return new Thermosiphon(); 

(empty constructor) and hoped for Dagger2 to pick up that I wanted the missing Heater to be injected, yet the Heater of the provided Thermosiphon is always null;

I verified though my HeaterComponent / HeaterModule are working fine and are able to provide a Heater.

Do I completey misunderstand the whole feature of 'Dagger satisfies constructor dependencies for you' or am I missing something?

回答1:

If you're using modules, then if you have two provider modules bound to the same component, then you'll be able to allow them to see the heater as a constructor parameter.

@Module
public class HeaterModule {
    @Provides
    @Singleton
    Heater heater() {
        return new Heater(); // if not using @Inject constructor
    }
}

@Module
public class ThermosiphonModule {
    @Provides
    @Singleton
    Thermosiphon thermosiphon(Heater heater) {
        return new Thermosiphon(heater); // if not using @Inject constructor
    }
}

@Singleton
@Component(modules={ThermosiphonModule.class, HeaterModule.class})
public interface SingletonComponent {
    Thermosiphon thermosiphon();
    Heater heater();

    void inject(Something something);
}

public class CustomApplication extends Application {
    private SingletonComponent singletonComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        this.singletonComponent = DaggerSingletonComponent.builder().build(); //.create();
    }

    public SingletonComponent getSingletonComponent() {
        return singletonComponent;
    }
}

But with constructor injection, you will also be able to provide objects of that given scope, or unscoped objects, as long as they have a @Inject constructor.

For example,

@Singleton
@Component // no modules
public interface SingletonComponent {
    Thermosiphon thermosiphon();
    Heater heater();

    void inject(Something something);
}

And

@Singleton
public class Heater {
    @Inject
    public Heater() {
    }
}

And

@Singleton
public class Thermosiphon {
    private Heater heater;

    @Inject
    public Thermosiphon(Heater heater) {
        this.heater = heater;
    }
}

Or

@Singleton
public class Thermosiphon {
    @Inject
    Heater heater;

    @Inject
    public Thermosiphon() {
    }
}


回答2:

For one, since you've annotated the constructor of Thermosiphon with @Inject, you don't need an @Provides method. Dagger uses this constructor to create an instance when needed. Just annotate the Thermosiphon class itself with @Singleton to preserve the singleton behavior.

If you do want to use an @Provides method, and to answer your question fully, you can specify the Heater as a parameter to the method:

@Module
public class ThermosiphonModule {

    @Provides
    @Singleton
    Thermosiphon provideThermosiphon(Heater heater) {
        return new Thermosiphon(heater);
    }

}