Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android with Dagger 2

Android with Dagger 2

2015/04/23 在 Android Taipei 的 talk

Chien Shuo (Kros)

August 27, 2015
Tweet

More Decks by Chien Shuo (Kros)

Other Decks in Programming

Transcript

  1. 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!");
  2. 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(); } }
  3. 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(); } }
  4. 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);
 } }
  5. 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");

  6. 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.
  7. 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.
  8. 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.
  9. Dagger API • @Module + @Provides: 提供相依性的機制 • @Inject: 要求提供相依性

    • @Component: modules 與 injections 之間的橋 樑,讓兩者能互通 • 另外有⼀一些語法糖可以使⽤用,使⽤用起來更⽅方便 • 被設計成可以拆成許多⼩小元件,並組合起來使⽤用
  10. Providing Dependencies • Modules 是⼀一些 classes,⽽而這些 classes 中的 methods 提供相依性。

    • 必須在 class 上加上 @Module • 必須在每個 method 上加上 @Provides
  11. public class NetworkModule { OkHttpClient provideOkHttpClient() { return new OkHttpClient();

    } TwitterApi provideTwitterApi(OkHttpClient client) { return new TwitterApi(client); } }
  12. @Module public class NetworkModule { OkHttpClient provideOkHttpClient() { return new

    OkHttpClient(); } TwitterApi provideTwitterApi(OkHttpClient client) { return new TwitterApi(client); } }
  13. @Module public class NetworkModule { !@Provides OkHttpClient provideOkHttpClient() { return

    new OkHttpClient(); } @Provides TwitterApi provideTwitterApi(OkHttpClient client) { return new TwitterApi(client); } }
  14. @Module public class NetworkModule { !@Provides @Singleton OkHttpClient provideOkHttpClient() {

    return new OkHttpClient(); } @Provides @Singleton TwitterApi provideTwitterApi(OkHttpClient client) { return new TwitterApi(client); } }
  15. Providing Dependencies • Modules 是⼀一些 classes,⽽而這些 classes 中的 methods 提供相依性。

    • 必須在 class 上加上 @Module • 必須在每個 method 上加上 @Provides • Modules 可以拆開成很多 module,也可以組合在 ⼀一起使⽤用
  16. @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); } }
  17. Requesting Dependencies • 必須要有 @Inject 的 annotation • 有三種 inject

    ⽅方式 • Constructor, field, and method injection.
  18. Constructor Injection • 在 Constructor 加上 @Inject • 表⽰示 Constructor

    的參數需要 dependency • 這些參數可以被使⽤用在 private 或 final fields.
  19. public class TwitterApplication { private final Tweeter tweeter; private final

    Timeline timeline; @Inject
 public TwitterApplication(Tweeter tweeter, Timeline timeline) {
 this.tweeter = tweeter; this.timeline = timeline;
 } //… }
  20. Method Injection • 在 methods 上加上 @Inject • 表⽰示 method

    的參數需要 dependency • Injection 發⽣生在物件被完全建⽴立之後 • 只有⼀一個合理的 use case: passing ‘this’ to a dependency.
  21. 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); } }
  22. Field Injection • 在 fields 上加上 @Inject • Field 不能為

    private 或是 final • Injection 發⽣生在物件被完全建⽴立之後 • 在 android 中最常⾒見到
  23. Components • Modules 與 injections 之間的橋樑,讓兩者能互 通 • Component 為

    injector,實際發⽣生 inject 的⼈人 • Scope 的概念
  24. TwitterComponent component = DaggerTwitterComponent.builder() .twitterModule(new TwitterModule(“JakeWharton")) .build(); @Module
 public class

    TwitterModule { private final String user; public TwitterModule(String user) {
 this.user = user; } // …
  25. 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); } } }
  26. @Singleton @Component(modules = { NetworkModule.class,
 TwitterModule.class,
 !})
 public interface TwitterComponent

    { TwitterApplication app(); } TwitterComponent component = DaggerTwitterComponent.builder() .twitterModule(newTwitterModule(“JakeWharton")) .build(); component.app().run();
  27. 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); } } }
  28. @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();
  29. @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…
  30. Components • Modules 與 injections 之間的橋樑,讓兩者能互 通 • Component 為

    injector,實際發⽣生 inject 的⼈人 • Scope 的概念
  31. @Component( dependencies = ApiComponent.class, modules = TwitterModule.class
 ) public interface

    TwitterComponent {
 void injectActivity(TwitterActivity activity); } @Singleton
 @Component(modules = NetworkModule.class) public interface ApiComponent { 
 }
  32. @Singleton
 @Component(modules = NetworkModule.class) public interface ApiComponent { TwitterApi api();


    } @Component( dependencies = ApiComponent.class, modules = TwitterModule.class
 ) public interface TwitterComponent {
 void injectActivity(TwitterActivity activity); }
  33. @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); } }
  34. ApiComponent apiComponent = Dagger_ApiComponent.create(); TwitterComponent twitterComponent = DaggerTwitterComponent.builder() .apiComponent(apiComponent) .twitterModule(new

    TwitterModule("JakeWharton"))
 .build(); TwitterActivity activity = // Android creates instance...
 component.injectActivity(activity);
  35. Scope Annotations • Only create a single instance. • @Singleton

    是最⼤大的 scope
 (可以想像是最上層的 scope) • ⾃自定 scope,可以讓程式更清楚,也可以有較短 的 lifecycle @Scope public @interface User {
 }
  36. @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); } }
  37. @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); } }
  38. @Component( dependencies = ApiComponent.class, modules = TwitterModule.class
 ) public interface

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

    interface TwitterComponent {
 void injectActivity(TwitterActivity activity); }
  40. 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); }
  41. 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();
 }
  42. Issues • Gained 13% of processor performance at google scale

    • No reflection at all • Less flexible
  43. 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/