I have a MainActivity which injects Presenter, presenter object injects interactor and interactor object injects APIHelper. All the providers of presenter, interactor and APIHelper are there in MainModule.
@Module
public class MainActivityModule {
private final MainActivity activity;
//Context context;
public MainActivityModule (MainActivity activity) {
this.activity = activity;
}
@Provides
@Singleton
public MainViewPresenter providesMainPresenter(){
return new MainPresenterImpl(activity);
}
@Provides
@Singleton
ListingInteractor providesInteractor( ){
return new ListingInteractorImpl(activity);
}
@Provides
@Singleton
ApiHelper providesAPI( ){
return new ApiHelper(activity);
}
}
I have injected the component in the MainActivity like:
DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule(MainActivity.this))
.build().inject(this);
In my Presenter implementation I have interactor like:
public class MainPresenterImpl implements MainViewPresenter {
Context context;
private MainView mainView;
// @Inject
ListingInteractor interactor; //here i get null interactor
MyScrollListener scrollListener;
public MainPresenterImpl(MainActivity activity) {
this.context = activity;
this.mainView = activity;
}
@Override
public void getCatFacts() {
interactor.getFacts();
}
My interactor implementation class has API helper whose constructor needs context
public class ListingInteractorImpl implements ListingInteractor{
private Context context;
@Inject
private APIHelper; // getting null APIHelper
public ListingInteractorImpl(Context context) {
this.context = context;
}
My component interface is like:
@Component(modules={MainActivityModule.class})
@Singleton
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
/*void inject(MainPresenterImpl presenter);*/
MainViewPresenter getMainPresenter();
ListingInteractor getInteractor();
ApiHelper getHelper();
}
but only presenter object is created in the MainActivity all other objects in presenter including interactor, APIHelper are null.According to dagger it should resolve all dependencies.
Change
MainPresenterImpl
&ListingInteractorImpl
constructors to following and precede them with@Inject
:Then in your module implementation:
Dagger is not magic. It will not magically insert objects wherever you want unless you tell it to do so.
To Dagger this is...nothing. You marked some field (
ListingInteractor
) for field injection, but unless you manually call a component to inject your object nothing will happen. Field injection should be reserved for Activities and Fragments where you can't add arguments to the constructor, not for your average classes.Instead of letting Dagger create
MainPresenterImpl
for you, you make a call tonew MainPresenterImpl()
yourself, only passing in the Activity. Since there is no call toMainPresenterImpl.interactor
, it will benull
. You're not using field injection, you're calling the constructor yourself and you're not assigning the field.Manually creating objects in modules should be reserved for objects that require further setup, like
Retrofit
orOkHttp
with their builders.If you want your fields to be set, you could use field injection and register your objects with the Component (those
inject(FieldInjectableClass clazz)
methods) and sprinklecomponent.inject(myObject)
throughout your code, which would be a really bad idea because you'd end up writing a lot of boilerplate that you don't need.The more reasonable way is to move your dependencies to the constructor, where they belong.
If you have a dependency on another class, why not declare it as such? But this still leaves the boilerplate of you creating the object yourself, instead of letting Dagger do its job.
That's why you should use Constructor Injection. As the name suggests, it's about the constructor. Just add the
@Inject
annotation:Now Dagger knows about this entry point to your class and can create it.
To let dagger handle things you could add the
@Singleton
scope to the class itself (annotate the class, not the constructor) and just delete the@Provides
method for it (there is no need for provides methods in modules for objects that don't need further setup), but since you're binding an Implementation to an Interface you still need to specify which class you want to bind to the interface.Since Dagger can create
MainPresenterImpl
with constructor injection you can return the implementation for your interface, and there is no need to update any code in case the constructor signature changes, as Dagger will just adapt the class instantiation accordingly.That's how to use constructor injection and bind implemenations to interfaces. And as mentioned, I recommend highly to read up on the basics. Make sure you understand what Dagger does and how it works. Be sure to know the difference between field and constructor injection, or when to use modules.
The time you invest now in learning Dagger will mean much less debugging and errors later on.
In case that your module is abstract or an interface, you can also make use of the
@Binds
method, where Dagger will just generate the boilerplate code above.