Dependency Injection

with Dagger2

František Gažo

github.com/FrantisekGazo

Android developer at

What is Dependency Injection?

You use it even without knowing

"Dependency injection is a software design pattern in which one or more dependencies are injected, or passed by reference, into a dependent object. This pattern separates the creation of object's dependencies from its own behaviour, which allows program designs to be loosely coupled and to follow the Inversion of Control and Single Responsibility principle."

Why?

  • reduce coupling 
  • more flexible
    
  • easier to test

How?

  • DIY
  • Library

RoboGuice

Dagger

No longer supported since August 2016
Deprecated since September 2016

Dagger 2

  • DI framework for both Java and Android
  • fully static, compile-time
  • version 1 created by Square
  • maintained by Google

Setup

dependencies {
    compile 'com.google.dagger:dagger:2.x'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.x'
}

API

3 main parts:

  • Target
  • Component
  • Module
MainActivity
AppComponent
AppModule
@Inject
@Component
@Module
@Provides

Let's code...

Qualifiers

@Qualifier
@Retention(RUNTIME)
public @interface UserName {
}

class UserInfoActivity extends Activity {

    @Inject
    @UserName
    String mUserName;
}
  • custom
  • standard
class UserInfoActivity extends Activity {

    @Inject
    @Named("user-name")
    String mUserName;
}
@Module
class UserModule {

    @Provides
    @Named("user-name")
    String provideUserName() {...}
}

Scopes

  • define dependency lifetime
  • application
  • user
  • activity
  • ...

Scopes

  • Dagger generates Component implementations
  • manage them yourself
  • be prepared!

Scopes

@Scope
@Retention(RUNTIME)
public @interface UserScope {
}
@Singleton
@Component(modules = {
    DataModule.class
})
interface AppComponent { ... }
  • custom
  • standard
@Module
class DataModule {

    @Provides
    @Singleton
    DB provideDatabase() {...}
}
bind Component to the Scope
Module cannot provide in different Scopes
@UserScope
@Subcomponent(modules = {
    UserModule.class
})
interface UserComponent { ... }
@Module
class UserModule {

    //...

    @Provides
    @UserScope
    USer provideUser() {...}
}
@Subcomponent
@Component
@?

Subcomponents

// parent

@Component(modules = ParentModule.class)
interface ParentComponent {

    ChildComponent childComponent();
//  ChildComponent childComponent(ChildModule m);
}

@Module
class ParentModule { ... }

// child

@Subcomponent(modules = ChildModule.class)
interface ChildComponent { ... }

@Module
class ChildModule { ... }
ParentComponent parent = DaggerParentComponent.create();
ChildComponent child = parent.childComponent();
//ChildComponent child = parent.childComponent(new ChildModule(...));

Subcomponents

// parent

@Component(modules = ParentModule.class)
interface ParentComponent {
    // define all public dependencies from Modules
}

@Module
class ParentModule { ... }

// child

@Component(
    dependencies = ParentComponent.class,
    modules = ChildModule.class
)
interface ChildComponent {
}

@Module
class ChildModule { ... }
ParentComponent parent = DaggerParentComponent.create();
ChildComponent child = DaggerChildComponent.builder()
                            .parentComponent(parent)
                          //.childModule(new ChildModule(...))
                            .build();

Testing

"you don’t need to use Dagger in your test at all"

end-to-end testing

  • Override bindings by subclassing modules (don’t do this!)
  • Separate component configurations
  • Use build flavors

More

Lazy injecting

Producers

...

Video about Dagger 2 (Jake Wharton)

Thank you

Dagger2

By František Gažo

Dagger2

  • 733