28

I am trying to use Dagger2 for DI, it works perfectly fine for Activity/Fragment related classes where there is a onCreate lifecycle event. Now I have a plain Java class which I want to be injected. Any ideas as to how to go about it would be appreciated. The code I have looks like this :

BasicMoviesUsecaseComponent.java -

@PerActivity
@Component(dependencies = AppComponent.class, modules = BasicMoviesUsecasesModule.class)
public interface BasicMoviesUsecasesComponent {
    void inject(PaymentsManager paymentsManager);
}

DatabaseModule.java -

    @Module
    public class DatabaseModule {
       @Provides @Singleton
       Realm provideRealmInstance(Context context) {

           return Realm.getInstance(context);
       }

       @Provides @Singleton
       DatabaseProvider provideDatabaseInstance(Realm realm) {

           return new DatabaseProvider(realm);
       }

       @Provides @Singleton
       SharedPreferences provideSharedPrefs(Context context) {

            return context.getSharedPreferences(context.getPackageName()+"_prefs", Context.MODE_PRIVATE);
       }

       @Provides @Singleton
       SharedPreferencesManager provideSharedPreferencesManager(SharedPreferences sharedPreferences) {
            return new SharedPreferencesManager(sharedPreferences);
       }

        @Provides @Singleton
        PaymentsManager providePaymentsManager(SharedPreferencesManager sharedPreferencesManager) {

              return new PaymentsManager(sharedPreferencesManager);

        }

}

AppComponent.java -

  @Singleton
  @Component(modules = {
    ApplicationModule.class,
    DomainModule.class,
    DatabaseModule.class
   })

public interface AppComponent {

    Bus bus();
    Realm realm();
    DatabaseProvider dbProvider();
    SharedPreferencesManager sharedPreferencesManager();
}

Here is the class I need to inject the SharedPreferencesManager into and I am unable to do so :

MyManager.java -

 private class MyManager {
    private SharedPreferencesManager manager;

    @Inject
    MyManager(SharedPreferencesManager manager){
          this.manager = manager;           
    } 

    private void initializeDependencyInjector() {

          BMSApplication app = BMSApplication.getInstance();

          DaggerBasicMoviesUsecasesComponent.builder()
                 .appComponent(app.getAppComponent())
                 .basicMoviesUsecasesModule(new BasicMoviesUsecasesModule())
                 .build().inject(PaymentsManager.this);
    }

}

How do I call initializeDependencyInjector() ?

Adnan Mulla
  • 2,872
  • 3
  • 25
  • 35

2 Answers2

45

You should generally use constructor injection whenever possible. The call to component.inject(myObject) is mostly to be used for objects which you can not instantiate yourself (like activities or fragments).

Constructor injection is basically what you already did:

private class MyManager {
    private SharedPreferencesManager manager;

    @Inject
    MyManager(SharedPreferencesManager manager){
          this.manager = manager;           
    } 
}

Dagger will create the object for you and pass in your SharedPreferencesManager. There is no need to call init or something similar.

The real question is how to obtain an object of MyManager. To do so, again, dagger will handle it for you.

By annotating the constructor with @Inject you tell dagger how it can create an object of that type. To use it, just inject it or declare it as a dependency.

private class MyActivity extends Activity {
    @Inject
    MyManager manager;

    public void onCreate(Bundle savedState){
        component.inject(this);  
    } 
}

Or just add a getter to a component (as long as SharedPreferenceManager can be provided, MyManager can also be instantiated):

@Component(dependencies = SharedPreferenceManagerProvidingComponent.class)
public interface MyComponent {

    MyManager getMyManager();
}
David Medenjak
  • 33,993
  • 14
  • 106
  • 134
  • How will this dependency be fulfilled `SharedPreferencesManager manager`? – eC Droid Jul 19 '17 at 12:26
  • @eCDroid You need to ensure that it can either be constructor injected and created, that a module provides it, that it is bound to a component, or that a parent or component dependency can provide it. It really is up to you on how you want to provide the dependency, the component just needs to be able to access it. – David Medenjak Jul 19 '17 at 12:31
  • Does this provides it in your case `dependencies = SharedPreferenceManagerProvidingComponent.class`? Also please explain this tag – eC Droid Jul 19 '17 at 12:40
  • what if you dont want MyManager to not be created by dagger and u need to create it yourself such as a ViewAdapter for a recyclerview? – Jono Feb 13 '18 at 11:20
  • @jonney then you would just inject what you need in parent activity/fragment and then pass it into the ViewAdapter's constructor I think. Correct me if I'm wrong. – nilsi Jan 02 '19 at 16:40
  • How to pass activity instance to its dependencies ? – K Pradeep Kumar Reddy Sep 29 '20 at 04:44
0

I also encounter this problem. I have MailgunService that I am using in one of my textfield validators. This validator is made in such way that I can define it in XML layout as app:rule="mailgun|email".

So basically I am accessing validator inside custom view implementation, this validator needs service, and I want to use dagger in order to not have to create all this httpclient, retrofits, etc. Which is dependency hell if created manually.

So I found such a way to do this.

First inside your AppComponent you do:

interface  AppComponent { 
    ...
    // getters
    fun getMailgunService(): IMailgunService
}

Then in Application you make

 companion object { lateinit var INSTANCE: MyApp }

Then inside your class where you want to inject IMailgun service from dagger AppComponent you can do

private var service: IMailgunService

 init {
        val component = DaggerAppComponent
            .builder()
            .application(CRMApp.INSTANCE)
            .build()

        service = component.getMailgunService()
    }

And it is injected and it works!

Michał Ziobro
  • 10,759
  • 11
  • 88
  • 143