Dagger 2 and interface implementation

I have a simple Dagger 2 test installation based on http://konmik.imtqy.com/snorkeling-with-dagger-2.html . It introduces a PreferenceLogger, which displays all the settings. In the introduced class, I can @Inject more classes.

public class MainActivity extends Activity { @Inject PreferencesLogger logger; @Inject MainPresenter presenter; @Override protected void onCreate(Bundle savedInstanceState) { MyApplication.getComponent().inject(this); presenter.doStuff(); logger.log(this); } } public class PreferencesLogger { @Inject OkHttpClient client; @Inject public PreferencesLogger() {} public void log(Contect context) { // this.client is available } } 

When I ran this, a logger is installed, and inside PreferencesLogger.log, OkHttpClient is correctly installed. Thus, this example works as expected. Now I am trying to create an MVP structure. There MainPresenter interface with implementation. In MainActivity, I set:

 @Inject MainPresenter presenter; 

so I can switch this MainPresenter to an alternative (debug or test) implementation. Of course, now I need a module to indicate which implementation I want to use.

 public interface MainPresenter { void doStuff(); } public class MainPresenterImpl implements MainPresenter { @Inject OkHttpClient client; public MainPresenterImpl() {} @Override public void doStuff() { // this.client is not available } } @Module public class MainActivityModule { @Provides MainPresenter provideMainPresenter() { return new MainPresenterImpl(); } } 

Now a problem arises when OkHttpClient is no longer entered. Of course, I could change the module to accept the OkHttpClient parameter, but I don't think this is the suggested way to do this. Is there a reason MainPresenterImpl is not entering correctly?

+7
java android dependency-injection mvp dagger-2
source share
2 answers

Unlike constructor embeddings, annotated @Inject dependency fields built in @Provides methods cannot be automatically entered. To be able to enter fields, a component is required that provides the field type in its modules and in the provider’s methods themselves; such an implementation is not available.

When the presenter field is entered in MainActivity , all that happens is the provider method is called and the presenter set to its return value. In your example, the no-args constructor does not initialize, and the provider method does not execute, so initialization does not.

However, the provider has access to instances of other types provided in the module through its parameters. I think that the use of parameters in the provider method is actually the proposed (even the only) way to "inject" the dependencies of the provided type, since it explicitly indicates them as dependencies inside the module, which allows the dagger to throw out a compilation error if they cannot be satisfied .

The reason she is currently not throwing an error is because MainPresenterImpl can get its OkHttpClient dependency if MainPresenterImpl and not MainPresenter was somewhere for injection purpose. The dagger cannot use the input / output method for the type of interface, because it cannot have injection fields as an interface and will not automatically enter fields of the implementation type, since it simply passes all the methods the provider returns.

+4
source share

You can enter MainPresenterImpl using the constructor insert.

 /* unscoped */ public class MainPresenterImpl implements MainPresenter { @Inject OkHttpClient client; @Inject public MainPresenterImpl() { } @Override public void doStuff() { // this.client is now available! :) } } @Module public class AppModule { private MyApplication application; public AppModule(MyApplication application) { this.application = application; } @Provides /* unscoped */ public MyApplication application() { return application; } } @Module public abstract class MainActivityModule { @Binds public abstract MainPresenter mainPresenter(MainPresenterImpl mainPresenterImpl); } 
+4
source share

All Articles