Dagger2 not resolving dependency all the way

寵の児 提交于 2019-12-02 07:44:48

Dagger is not magic. It will not magically insert objects wherever you want unless you tell it to do so.

public class MainPresenterImpl implements MainViewPresenter {
  // ... other fields ...
  @Inject
  ListingInteractor interactor;

  public MainPresenterImpl(MainActivity activity) {
    this.context = activity;
    this.mainView = activity;
  }
}

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.

@Provides
@Singleton
MainViewPresenter providesMainPresenter(){
  return new MainPresenterImpl(activity);
}

Instead of letting Dagger create MainPresenterImpl for you, you make a call to new MainPresenterImpl() yourself, only passing in the Activity. Since there is no call to MainPresenterImpl.interactor, it will be null. 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 or OkHttp 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 sprinkle component.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.

public MainPresenterImpl(MainActivity activity, ListingInteractor interactor) { /* ... */ }

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:

@Inject // marked for constructor injection!
public MainPresenterImpl(MainActivity activity, ListingInteractor interactor) { /* ... */ }

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.

@Provides
@Singleton
MainViewPresenter providesMainPresenter(MainPresenterImpl implementation){
  return implementation;
}

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.

@Binds
@Singleton
MainViewPresenter providesMainPresenter(MainPresenterImpl implementation);

Change MainPresenterImpl & ListingInteractorImpl constructors to following and precede them with @Inject:


    @Inject
    public MainPresenterImpl(MainActivity activity, ListingInteractor interactor) {...}

    @Inject
    public ListingInteractorImpl(Context context, APIHelper helper) {...}

Then in your module implementation:


    @Provides
    @Singleton
    public MainViewPresenter providesMainPresenter(ListingInteractor interactor){
        return new MainPresenterImpl(activity, interactor);
    }

    @Provides
    @Singleton
    ListingInteractor providesInteractor(APIHelper helper){
        return new ListingInteractorImpl(activity, helper);
    }


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!