WISHY
WISHY

Reputation: 12009

Dagger 2 method injection?

I have 2 classes for which I want dependency injection to happen. Basically both need each other's objects to perform some task.

First class

public class AppMobilePresenter {
AppPresenter appPresenter;

@Inject
public AppMobilePresenter(AppPresenter appPresenter) {
    this.appPresenter = appCMSPresenter;
}
}

Its module

@Module
public class AppMobilePresenterModule {
@Provides
@Singleton
public AppMobilePresenter providesAppMobilePresenter(AppPresenter appPresenter) {
    return new AppMobilePresenter(appPresenter);
}
}

Second Class

public class AppPresenter {
AppMobilePresenter appMobilePresenter;

@Inject
public AppPresenter() {
}

@Inject 
void setAppMobilePresenter(AppMobilePresenter appMobilePresenter){
    this.appMobilePresenter=appMobilePresenter;
}
}

Its modules

@Module(includes = { AppMobilePresenterModule.class})
public class AppPresenterModule {
@Provides
@Singleton
public AppPresenter providesAppPresenter() {
    return new AppPresenter();
}
}

I have a common component for both

@Singleton
@Component(modules = {AppPresenterModule.class})
public interface AppPresenterComponent {
AppPresenter appPresenter();
}

After building the component from my application class and running the application I get AppMobilePresenter object null in AppPresenter class. Is there also something else need to be done for method injection.

Upvotes: 1

Views: 1342

Answers (1)

Jeff Bowman
Jeff Bowman

Reputation: 95774

Method injection doesn't happen when you call constructors, as you do in your @Provides methods; if you want method injection to happen, Dagger needs to call your @Inject-annotated constructor in its generated code.

It looks like you'd prefer constructor injection, which is safer anyway, but are trying for method injection just to avoid a dependency cycle. Unfortunately, that won't work. Instead, switch back to constructor injection and use the technique shown here:

@Singleton
public class AppMobilePresenter {
  AppPresenter appPresenter;

  @Inject
  public AppMobilePresenter(AppPresenter appPresenter) {
    this.appPresenter = appCMSPresenter;
  }
}

@Singleton
public class AppPresenter {
  Provider<AppMobilePresenter> appMobilePresenterProvider;

  @Inject
  public AppPresenter(Provider<AppMobilePresenter> appMobilePresenterProvider) {
    this.appMobilePresenterProvider = appMobilePresenterProvider;
  }
}

The code above can use your same Component, and does not require any Modules. The one caveat is that to get to AppMobilePresenter from AppPresenter, you'll need to call appMobilePresenterProvider.get(), which you can call anywhere except for constructors and @Inject methods. This solves the construction problem: Dagger otherwise couldn't create AppMobilePresenter without first creating an AppPresenter, and couldn't create AppPresenter without first creating AppMobilePresenter. It can create a Provider, though, and provide the instance when you call it later.

If future readers really need field or method injection, they can leave your @Inject constructors and methods alone while removing the Modules and switching to method-inject a Provider<AppMobilePresenter>, which is necessary because method injection has the same construction-order dependency cycle concerns that constructor injection does.

Upvotes: 1

Related Questions