Edgar Da Silva Fernandes Edgar Da Silva Fernandes - 1 month ago 7
Android Question

How to implement Dependency Injection using Dagger2 on the given scenario? (Manage injection hierarchy on Dagger2)

Suppose I have the following classes:

class Foo {}

class Bar {
Foo mFoo = new Foo();
}

class MyActivity extends AppCompatActivity {
Bar mBar = new Bar();

@Override
protected void onCreate (Bundle savedInstance) {
super(savedInstance);
}
}


From the code above it can be seen that MyActivity depends on Bar and Bar depends on Foo. What is the correct way to implement dependency injection using Dagger2?




My Approach...



So far, the way I've been dealing with this type os scenario was:

Configuration

@Singleton
@Component(
modules = {
MainModule.class,
})
public interface MainComponent {
void inject(MyActivity myActivity);

void inject(Bar bar);
}

@Module
class MainModule {
@Provides
@Singleton
Foo provideFoo() {
return new Foo();
}

@Provides
@Singleton
Bar provideBar() {
return new Bar();
}
}


Injection

class Bar {
@Inject Foo mFoo;

Bar() {inject(this);}
}

class MyActivity extends AppCompatActivity {
@Inject Bar mBar;

@Override
protected void onCreate (Bundle savedInstance) {
super(savedInstance);
inject(this);
}
}





Problem is, according to this answer, it is not supposed to work like that,
Bar
should not call
inject
and have
Foo
passed as parameter. But, what if I need singletons instances of
Foo
in other parts of my project? How should I use Dagger2 to achieve the given scenario?

Answer

If you change the signature of the constructor of Bar to the following you should achieve the effect that you want (constructor injection).

class Bar {
    Foo foo;

    @Inject
    Bar(Foo foo) {
        this.foo = foo;
    }        
}

Then you just need to specify the dependency of Bar in the provider by writing it as a method parameter like this:

@Provides Bar provideBar(Foo foo)

Since Foo and Bar are known to dagger through the @Provide methods, dagger will automagically create an instance of Foo to obtain an instance of Bar. Constructor injection like this will have the added advantage of making your code easy to unit test. In your test, you can swap out a real Foo with a mock Foo and test the interaction of Foo on Bar.

Property injection is best only when you don't have access to the constructor (like in Android Activity and Service). For your other dependencies, it's probably best to use constructor injection.