Yura Buyaroff
Yura Buyaroff

Reputation: 1736

Dagger 2 - Provides methods to have dependencies of their own

I'm trying to understand and implement Dagger 2. I've already read a lot of different tutorials and official documentation. I think I understand it in general but I still can not understand some simple points (while I wrote it I've found solution for some but..):

It's possible for @Provides methods to have dependencies of their own.

When it's possible?

What I see it's possible to get "component contains a dependency cycle".

Can someone help me to understand cases when it possible and when it not possible.
Thanks.

Upvotes: 1

Views: 1123

Answers (2)

EpicPandaForce
EpicPandaForce

Reputation: 81588

Actually, you can use qualifiers (@Named("something") annotation) to get multiple different type of implementation for a given dependency.

 @Singleton 
 @Component(modules = ApplicationModule.class)
 public interface ApplicationComponent {
     void inject(BaseActivity baseActivity);

     @Named("first")
     BaseNavigator firstNavigator();
     @Named("second")
     BaseNavigator secondNavigator();

     Context context();
     //...
 }

@Module
public class ApplicationModule {
    private final AndroidApplication application;

    public ApplicationModule(AndroidApplication application) {
        this.application = application;
    }

    @Provides
    @Singleton
    @Named("first")
    BaseNavigator provideFirstNavigator() {
        return new SomeNavigator();
    }

    @Provides
    @Singleton
    @Named("second")
    BaseNavigator provideSecondNavigator() {
        return new OtherNavigator();
    }

    @Provides
    Context provideApplicationContext() {
        return this.application;
    }

}

public abstract class BaseActivity extends Activity {

    @Inject
    @Named("second")
    BaseNavigator navigator;

Upvotes: 3

Yura Buyaroff
Yura Buyaroff

Reputation: 1736

After very long way of many experiments I've found the answer. I'm making this answer as cue card for myself and hope it can help other daggers jedis.

So we have dagger structure

  • AndroidApplication
  • BaseActivity
  • Navigator
  • ApplicationComponent
  • ApplicationModule
  • ...

ApplicationComponent.class

 @Singleton 
 @Component(modules = ApplicationModule.class)
 public interface ApplicationComponent {
     void inject(BaseActivity baseActivity);

     Navigator navigator();
     Context context();
     //...
 }

ApplicationModule.class

@Module
public class ApplicationModule {
    private final AndroidApplication application;

    public ApplicationModule(AndroidApplication application) {
        this.application = application;
    }

    @Provides
    @Singleton
    Navigator provideNavigator() {
        return new Navigator();
    }

    @Provides
    @Singleton
    Context provideApplicationContext() {
        return this.application;
    }

}

Navigator.class

@Singleton
public class Navigator implements BaseNavigator {

    public Navigator() {}

}

BaseActivity.class

public abstract class BaseActivity extends Activity {

    @Inject
    Navigator navigator;

    //code here

}

This code will work and BaseActivity will get navigator as new Navigator() provided by ApplicationModule.

But if you have several implementation of BaseNavigator class you can get some certain implementation for example Navigator class without creating new instance manually.

*This construction will give you "component contains a dependency cycle"

        @Provides
        @Singleton
        Navigator provideNavigator(Navigator navigator) {
            return navigator;
        }

You can do this:

ApplicationComponent.class

 @Singleton 
 @Component(modules = ApplicationModule.class)
 public interface ApplicationComponent {
     void inject(BaseActivity baseActivity);

     BaseNavigator navigator(); // changed to interface type
     Context context();
     //...
 }

ApplicationModule.class

@Module
public class ApplicationModule {
    private final AndroidApplication application;

    public ApplicationModule(AndroidApplication application) {
        this.application = application;
    }

    @Provides
    @Singleton
    BaseNavigator provideNavigator(Navigator navigator) {
        return navigator;
    } // this will return interface type but with implementation you needed

    @Provides
    @Singleton
    Context provideApplicationContext() {
        return this.application;
    }

}

Navigator.class

@Singleton
public class Navigator implements BaseNavigator {

    @Inject // don't forget to add this annotation to the constructor
    public Navigator() {}

}

BaseActivity.class

public abstract class BaseActivity extends Activity {

    @Inject
    BaseNavigator navigator;// changed to interface type

    //code here

}

Now you did not create new instance for Navigator, Dagger did it instead of you in its generated factory.

Upvotes: 0

Related Questions