Dependency Injection
with Dagger2
František Gažo
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
- 784