Android with Dagger 2
⿈黃千碩 / Kros
iOS/Android Developer
Dependency Injection
• 中⽂文 - 相依性注⼊入?
• No “new”, dependencies come to you.
Dependency Injection
• ⼀一種 Design Pattern
• 最快速,且不⽤用任何 Liberary 即可達成
• 其實每個 app 中都已經有實作 DJ
public class Tweeter {

public void tweet(String tweet) {
TwitterApi api = new TwitterApi();
api.postTweet("JakeWharton", tweet);
}
}
public class TwitterApi {

public void postTweet(String user, String tweet) {
OkHttpClient client = new OkHttpClient();
Request request = // TODO build POST request…
client.newCall(request).execute();
}
Tweeter tweeter = new Tweeter();

tweeter.tweet("Hello, #Devoxx 2014!");
public class TwitterApi {

private final OkHttpClient client = new OkHttpClient();
public void postTweet(String user, String tweet) {
Request request = // TODO build POST request
client.newCall(request).execute();
}
}
public class TwitterApi {

private final OkHttpClient client;
public TwitterApi(OkHttpClient client) {
this.client = client;
}
public void postTweet(String user, String tweet) {
Request request = // TODO build POST request
client.newCall(request).execute();
}
}
public class Tweeter {

private final TwitterApi api = new TwitterApi(new OkHttpClient());

private final String user;
public Tweeter(String user) {
this.user = user;
}
public void tweet(String tweet) {
api.postTweet(user, tweet);

}
}
public class Tweeter {

private final TwitterApi api = new TwitterApi(new OkHttpClient());

private final String user;
public Tweeter(String user) {
this.user = user;
}
public void tweet(String tweet) {
api.postTweet(user, tweet);

}
}
Tweeter tweeter = new Tweeter("JakeWharton");

tweeter.tweet("Hello, #Devoxx 2014!");

tweeter.tweet("#Hungover #Dagger");

Libraries
• Spring
• Guice
• Dagger (v1)
• PicoContainer
• CDI
Guice
• Developed at Google by Bob Lee, later Jesse
Wilson, others.
• Adopted and maintained by Java Core Libraries
team. Powerful, dynamic, well-tested, wide-
spread, etc...
• Configuration problems occur at runtime.
• Slow initialization, slow injection, memory
concerns.
Dagger (v1)
• Developed at Square by Jesse Wilson advised by Bob
Lee.
• Initially targeted at highly resource constrained
environments.
• Static analysis of all dependencies and injection points.
• Fail as early as possible (compile-time, not runtime)
• Eliminate reflection on methods, fields, and annotations.
Dagger (v2)
• Proposed and implemented by Java Core
Libraries team.
• Eliminate runtime library and generated code
overhead.
• Shift remaining runtime analysis to compile time.
• Scoping with annotations and associated static
analysis.
Dagger API
• @Module + @Provides: 提供相依性的機制
• @Inject: 要求提供相依性
• @Component: modules 與 injections 之間的橋
樑,讓兩者能互通
• 另外有⼀一些語法糖可以使⽤用,使⽤用起來更⽅方便
• 被設計成可以拆成許多⼩小元件,並組合起來使⽤用
Providing Dependencies
• Modules 是⼀一些 classes,⽽而這些 classes 中的
methods 提供相依性。
• 必須在 class 上加上 @Module
• 必須在每個 method 上加上 @Provides
public class NetworkModule {
OkHttpClient provideOkHttpClient() {
return new OkHttpClient();
}
TwitterApi provideTwitterApi(OkHttpClient client) {
return new TwitterApi(client);
}
}
@Module
public class NetworkModule {
OkHttpClient provideOkHttpClient() {
return new OkHttpClient();
}
TwitterApi provideTwitterApi(OkHttpClient client) {
return new TwitterApi(client);
}
}
@Module
public class NetworkModule {
!@Provides
OkHttpClient provideOkHttpClient() {
return new OkHttpClient();
}
@Provides
TwitterApi provideTwitterApi(OkHttpClient client) {
return new TwitterApi(client);
}
}
@Module
public class NetworkModule {
!@Provides @Singleton
OkHttpClient provideOkHttpClient() {
return new OkHttpClient();
}
@Provides @Singleton
TwitterApi provideTwitterApi(OkHttpClient client) {
return new TwitterApi(client);
}
}
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Providing Dependencies
• Modules 是⼀一些 classes,⽽而這些 classes 中的
methods 提供相依性。
• 必須在 class 上加上 @Module
• 必須在每個 method 上加上 @Provides
• Modules 可以拆開成很多 module,也可以組合在
⼀一起使⽤用
@Module

public class TwitterModule {
private final String user;
public TwitterModule(String user) {

this.user = user;
}
@Provides @Singleton
Tweeter provideTweeter(TwitterApi api) {
return new Tweeter(api, user);
}
@Provides @Singleton
Timeline provideTimeline(TwitterApi api) {
return new Tweeter(api, user);
}
}
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
TwitterModule#provideTweeter
TwitterModule#provideTimeline
Tweeter
Timeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
TwitterModule#provideTweeter
TwitterModule#provideTimeline
Tweeter
Timeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
TwitterModule#provideTweeter
TwitterModule#provideTimeline
Tweeter
Timeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
TwitterModule#provideTweeter
TwitterModule#provideTimeline
Tweeter
Timeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
TwitterModule#provideTweeter
TwitterModule#provideTimeline
Tweeter
Timeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
Tweeter
Timeline
TwitterModule#provideTweeter
TwitterModule#provideTimeline
OkHttpClient
Providing Dependencies
NetworkModule#provideOkHttpClient
TwitterApi NetworkModule#provideTwitterApi
TwitterModule#provideTweeter
TwitterModule#provideTimeline
Tweeter
Timeline
Requesting Dependencies
• 必須要有 @Inject 的 annotation
• 有三種 inject ⽅方式
• Constructor, field, and method injection.
Constructor Injection
• 在 Constructor 加上 @Inject
• 表⽰示 Constructor 的參數需要 dependency
• 這些參數可以被使⽤用在 private 或 final fields.
public class TwitterApplication {
private final Tweeter tweeter;
private final Timeline timeline;
@Inject

public TwitterApplication(Tweeter tweeter, Timeline timeline) {

this.tweeter = tweeter;
this.timeline = timeline;

}
//…
}
Method Injection
• 在 methods 上加上 @Inject
• 表⽰示 method 的參數需要 dependency
• Injection 發⽣生在物件被完全建⽴立之後
• 只有⼀一個合理的 use case: passing ‘this’ to a
dependency.
public class TwitterApplication {
private final Tweeter tweeter;
private final Timeline timeline;
@Inject

public TwitterApplication(Tweeter tweeter, Timeline timeline) {

this.tweeter = tweeter;
this.timeline = timeline;

}
@Inject

public void enableStreaming(Streaming streaming) {

streaming.register(this);
}
}
Field Injection
• 在 fields 上加上 @Inject
• Field 不能為 private 或是 final
• Injection 發⽣生在物件被完全建⽴立之後
• 在 android 中最常⾒見到
public class TwitterApplication extends Activity {
@Inject Tweeter tweeter;
@Inject Timeline timeline;
// ...

}
Components
• Modules 與 injections 之間的橋樑,讓兩者能互
通
• Component 為 injector,實際發⽣生 inject 的⼈人
• Scope 的概念
@Singleton
@Component(modules = {
NetworkModule.class,

TwitterModule.class,

!})

public interface TwitterComponent {


}
@Singleton
@Component(modules = {
NetworkModule.class,

TwitterModule.class,

!})

public interface TwitterComponent {
Tweeter tweeter();

Timeline timeline();
}
TwitterComponent component = DaggerTwitterComponent.builder()
.twitterModule(new TwitterModule(“JakeWharton"))
.build();
TwitterComponent component = DaggerTwitterComponent.builder()
.twitterModule(new TwitterModule(“JakeWharton"))
.build();
@Module

public class TwitterModule {
private final String user;
public TwitterModule(String user) {

this.user = user;
}
// …
TwitterComponent component = DaggerTwitterComponent.builder()
.twitterModule(new TwitterModule(“JakeWharton"))
.build();
Tweeter tweeter = component.tweeter();
tweeter.tweet("Hello, #Devoxx 2014!");
public class TwitterApplication implements Runnable {

private final Tweeter tweeter;

private final Timeline timeline;
@Inject

public TwitterApplication(Tweeter tweeter, Timeline timeline) {

this.tweeter = tweeter;
this.timeline = timeline;}
@Override
public void run() {
tweeter.tweet("Hello #Devoxx 2014!”);
timeline.loadMore(20);

for (Tweet tweet : timeline.get()) {
System.out.println(tweet);
}
}
}
@Singleton
@Component(modules = {
NetworkModule.class,

TwitterModule.class,

!})

public interface TwitterComponent {
TwitterApplication app();
}
@Singleton
@Component(modules = {
NetworkModule.class,

TwitterModule.class,

!})

public interface TwitterComponent {
TwitterApplication app();
}
TwitterComponent component = DaggerTwitterComponent.builder()
.twitterModule(newTwitterModule(“JakeWharton"))
.build();
component.app().run();
public class TwitterApplication implements Runnable {

@Inject Tweeter tweeter;

@Inject Timeline timeline;
@Inject

public TwitterApplication(Tweeter tweeter, Timeline timeline) {

this.tweeter = tweeter;
this.timeline = timeline;}
@Override
public void run() {
tweeter.tweet("Hello #Devoxx 2014!”);
timeline.loadMore(20);

for (Tweet tweet : timeline.get()) {
System.out.println(tweet);
}
}
}
@Singleton
@Component(modules = {
NetworkModule.class,

TwitterModule.class,

!})

public interface TwitterComponent {
void injectApp(TwitterApplication app);
}
@Singleton
@Component(modules = {
NetworkModule.class,

TwitterModule.class,

!})

public interface TwitterComponent {
void injectApp(TwitterApplication app);
}
TwitterComponent component = DaggerTwitterComponent.builder()
.twitterModule(newTwitterModule(“JakeWharton"))
.build();
TwitterApplication app = new TwitterApplication();

component.injectApp(app);
app.run();
@Singleton
@Component(modules = {
NetworkModule.class,

TwitterModule.class,

!})

public interface TwitterComponent {
void injectActivity(TwitterActivity activity);
}
TwitterComponent component = DaggerTwitterComponent.builder()
.twitterModule(newTwitterModule(“JakeWharton"))
.build();
TwitterActivity activity = // Android creates instance...

component.injectActivity(activity);
// use tweet and timeline in activity…
Components
• Modules 與 injections 之間的橋樑,讓兩者能互
通
• Component 為 injector,實際發⽣生 inject 的⼈人
• Scope 的概念
@Component(
dependencies = ApiComponent.class,
modules = TwitterModule.class

)
public interface TwitterComponent {

void injectActivity(TwitterActivity activity);
}
@Singleton

@Component(modules = NetworkModule.class)
public interface ApiComponent {


}
@Singleton

@Component(modules = NetworkModule.class)
public interface ApiComponent {
TwitterApi api();

}
@Component(
dependencies = ApiComponent.class,
modules = TwitterModule.class

)
public interface TwitterComponent {

void injectActivity(TwitterActivity activity);
}
@Module

public class TwitterModule {
private final String user;
public TwitterModule(String user) {

this.user = user;
}
@Provides @Singleton
Tweeter provideTweeter(TwitterApi api) {
return new Tweeter(api, user);
}
@Provides @Singleton
Timeline provideTimeline(TwitterApi api) {
return new Tweeter(api, user);
}
}
ApiComponent apiComponent = Dagger_ApiComponent.create();
TwitterComponent twitterComponent = DaggerTwitterComponent.builder()
.apiComponent(apiComponent)
.twitterModule(new TwitterModule("JakeWharton"))

.build();
TwitterActivity activity = // Android creates instance...

component.injectActivity(activity);
Scope Annotations
• Only create a single instance.
• @Singleton 是最⼤大的 scope

(可以想像是最上層的 scope)
• ⾃自定 scope,可以讓程式更清楚,也可以有較短
的 lifecycle
@Scope
public @interface User {

}
@Module

public class TwitterModule {
private final String user;
public TwitterModule(String user) {

this.user = user;
}
@Provides
Tweeter provideTweeter(TwitterApi api) {
return new Tweeter(api, user);
}
@Provides
Timeline provideTimeline(TwitterApi api) {
return new Tweeter(api, user);
}
}
@Module

public class TwitterModule {
private final String user;
public TwitterModule(String user) {

this.user = user;
}
@Provides @User
Tweeter provideTweeter(TwitterApi api) {
return new Tweeter(api, user);
}
@Provides @User
Timeline provideTimeline(TwitterApi api) {
return new Tweeter(api, user);
}
}
@Component(
dependencies = ApiComponent.class,
modules = TwitterModule.class

)
public interface TwitterComponent {

void injectActivity(TwitterActivity activity);
}
@User
@Component(
dependencies = ApiComponent.class,
modules = TwitterModule.class

)
public interface TwitterComponent {

void injectActivity(TwitterActivity activity);
}
Dagger 1
public abstract class ObjectGraph {

public static ObjectGraph create(Object... modules) {}

public abstract ObjectGraph plus(Object... modules);

public abstract void validate();

public abstract void injectStatics();

public abstract <T> T get(Class<T> type);

public abstract <T> T inject(T instance);
}
public @interface Module {

Class<?>[] injects() default { };

Class<?>[] staticInjections() default { };

Class<?>[] includes() default { };

Class<?> addsTo() default Void.class;

boolean overrides() default false;

boolean complete() default true;

boolean library() default true;
}
public @interface Provides {

enum Type { UNIQUE, SET }

Type type() default Type.UNIQUE;
}
public interface Lazy<T> {

T get();
}
public interface MembersInjector<T> {

void injectMembers(T instance);
}
Dagger 2
public @interface Component {

Class<?>[] modules() default {};
Class<?>[] dependencies()default {};

}
public @interface Module {
Class<?>[] includes() default {};
}
public @interface Provides {
}
public @interface MapKey {
boolean unwrapValue();
}
public interface Lazy<T> {
T get();

}
Issues
• Gained 13% of processor performance at
google scale
• No reflection at all
• Less flexible
Demo
https://github.com/ch8908/djdemo
Reference
• DAGGER 2 - A New Type of dependency injection

https://www.youtube.com/watch?v=oK_XtfXPkqw
• Dependency Injection with Dagger 2

https://speakerdeck.com/jakewharton/
dependency-injection-with-dagger-2-devoxx-2014
• The Future of Dependency Injection with Dagger 2

https://www.parleys.com/tutorial/
5471cdd1e4b065ebcfa1d557/

Android with dagger_2