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

DI @ Android

DI @ Android

Experience of Dependency Injection with Robots

Alex Korovyansky

July 19, 2014
Tweet

More Decks by Alex Korovyansky

Other Decks in Programming

Transcript

  1. DI @ Android Experience of Dependency Injection with Robots Alex

    Korovyansky Thumbtack Expertise Day Jul 19, 2014
  2. Dependency Injection • Software design pattern that implements inversion of

    control and allows a program design to follow the dependency inversion principle. The term was coined by Martin Fowler. 2
  3. Dependency Injection • Software design pattern that implements inversion of

    control and allows a program design to follow the dependency inversion principle. The term was coined by Martin Fowler. • Separates behaviour of something from its required classes 2
  4. Dependency Injection • Software design pattern that implements inversion of

    control and allows a program design to follow the dependency inversion principle. The term was coined by Martin Fowler. • Separates behaviour of something from its required classes 2 Component Service
  5. ! ! public class Component { private final Service service;

    public Component() { this.service = new ServiceImpl(); } public void doStuff() { return service.doStuff(); } } 3 ? ! ! ! public interface Service { public void doStuff(); }
  6. 4 ! ! ! public class CatsService implements Service {

    @Override public void doStuff() { System.out.println("Cats are better than dogs!") } } ! public class DogsService implements Service { @Override public void doStuff() { System.out.println("Dogs are better than cats!") } }
  7. ! ! public class Component { private final Service service;

    public Component() { this.service = new CatsService(); } public void doStuff() { return service.doStuff(); } } 5 ? ! ! ! public interface Service { public void doStuff(); }
  8. 8 ! ! ! public class Component { private final

    Service service; public Component(Service service) { this.service = service; } public void doStuff() { return service.doStuff(); } } ^^ Constructor Injection ^^
  9. Advantages of DI • Loosely coupled programs • Following single

    responsibility principle • Easy to write tests / extend / maintain 11
  10. Advantages of DI • Loosely coupled programs • Following single

    responsibility principle • Easy to write tests / extend / maintain • Reduction of boilerplate code 11
  11. Advantages of DI • Loosely coupled programs • Following single

    responsibility principle • Easy to write tests / extend / maintain • Reduction of boilerplate code • Parallel development 11
  12. Advantages of DI • Loosely coupled programs • Following single

    responsibility principle • Easy to write tests / extend / maintain • Reduction of boilerplate code • Parallel development • … 11
  13. Guice • Powerful, dynamic, well-tested, wide-spread, etc… • Canonical standard

    for dependency injection • Configuration problems fail at runtime 14
  14. Guice • Powerful, dynamic, well-tested, wide-spread, etc… • Canonical standard

    for dependency injection • Configuration problems fail at runtime • Slow initialization, slow injection, memory problems 14
  15. 15

  16. 17

  17. “ObjectGraph” goals • Static analysis of all dependencies and injections

    • Fail as early as possible (compile-time, not runtime) 18
  18. “ObjectGraph” goals • Static analysis of all dependencies and injections

    • Fail as early as possible (compile-time, not runtime) • Eliminate reflection on methods and annotations at runtime 18
  19. “ObjectGraph” goals • Static analysis of all dependencies and injections

    • Fail as early as possible (compile-time, not runtime) • Eliminate reflection on methods and annotations at runtime • Have negligible memory impact 18
  20. “ObjectGraph” Development • ~5 weeks of heads-down work by Jesse

    Wilson • Bob Lee served as technical advisor 19
  21. “ObjectGraph” Development • ~5 weeks of heads-down work by Jesse

    Wilson • Bob Lee served as technical advisor • “Giant” boolean switch in Square’s applications 19
  22. “ObjectGraph” Development • ~5 weeks of heads-down work by Jesse

    Wilson • Bob Lee served as technical advisor • “Giant” boolean switch in Square’s applications • 2 weeks after, they dropped Guice completely 19
  23. “ObjectGraph” Development • ~5 weeks of heads-down work by Jesse

    Wilson • Bob Lee served as technical advisor • “Giant” boolean switch in Square’s applications • 2 weeks after, they dropped Guice completely • Renamed to Dagger before first release 19
  24. “ObjectGraph” Development • ~5 weeks of heads-down work by Jesse

    Wilson • Bob Lee served as technical advisor • “Giant” boolean switch in Square’s applications • 2 weeks after, they dropped Guice completely • Renamed to Dagger before first release • Open sourced — http://github.com/square/dagger 19
  25. Dagger • ObjectGraph: central dependency manager and injector • @Module

    + @Provides: mechanism for providing dependencies 22
  26. Dagger • ObjectGraph: central dependency manager and injector • @Module

    + @Provides: mechanism for providing dependencies • @Inject: mechanism for requesting dependencies 22
  27. Dagger • ObjectGraph: central dependency manager and injector • @Module

    + @Provides: mechanism for providing dependencies • @Inject: mechanism for requesting dependencies • Plus some other sugar, magic and conventions 22
  28. Providing Dependencies • Modules are classes that provide dependencies •

    @Module annotation on the class • @Provider annotation on a method indicates that its return type is a dependency 23
  29. 24 public class NetworkModule { public OkHttpClient provideOkHttpClient() { return

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

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

    { return new OkHttpClient(); } @Provides public TwitterApi provideTwitterApi(OkHttpClient client) { return new TwitterApi(client); } }
  32. 27 @Module public class NetworkModule { @Provides @Singleton public OkHttpClient

    provideOkHttpClient() { return new OkHttpClient(); } @Provides @Singleton public TwitterApi provideTwitterApi(OkHttpClient client) { return new TwitterApi(client); } }
  33. Providing Dependencies • Modules are classes that provide dependencies •

    @Module annotation on the class • @Provider annotation on a method indicates that its return type is a dependency 29
  34. Providing Dependencies • Modules are classes that provide dependencies •

    @Module annotation on the class • @Provider annotation on a method indicates that its return type is a dependency • Designed to be composed together 29
  35. 30 @Module public class TwitterModule { private final String user;

    public TwitterModule(String user) { this.user = user; } @Provides @Singleton public Tweeter provideTweeter(TwitterApi api) { return new Tweeter(api, user); } ! @Provides @Singleton public Timeline provideTimeline(TwitterApi api) { return new Timeline(api, user); } }
  36. Listing Injection Points • All injection points must be listed

    on a module • Used for aggressive static analysis 32
  37. Listing Injection Points • All injection points must be listed

    on a module • Used for aggressive static analysis • Potentially not needed for full compilation... 32
  38. Listing Injection Points • All injection points must be listed

    on a module • Used for aggressive static analysis • Potentially not needed for full compilation... • ...but absolutely required for incremental compilation 32
  39. 33 @Module public class ExampleModule { @Provides @Singleton Foo provideFoo()

    { return new Foo(); } @Provides @Singleton Bar provideBar() { return new Bar(); } }
  40. 34 @Module( injects = { Component1.class, ComponentN.class } ) @Module

    public class ExampleModule { @Provides @Singleton Foo provideFoo() { return new Foo(); } @Provides @Singleton Bar provideBar() { return new Bar(); } }
  41. Constructor Injection • @Inject on a single constructor • All

    constructor arguments are dependencies 36
  42. Constructor Injection • @Inject on a single constructor • All

    constructor arguments are dependencies • Dependencies can be stored in private and final fields 36
  43. 37 public class TweeterApp { private final Tweeter tweeter; private

    final Timeline timeline; @Inject public TweeterApp(Tweeter tweeter, Timeline timeline){ this.tweeter = tweeter; this.timeline = timeline; } // ... }
  44. Constructor Injection • @Inject on a single constructor • All

    constructor arguments are dependencies • Dependencies can be stored in private and final fields 38
  45. Constructor Injection • @Inject on a single constructor • All

    constructor arguments are dependencies • Dependencies can be stored in private and final fields • Dagger must create the object 38
  46. Constructor Injection • @Inject on a single constructor • All

    constructor arguments are dependencies • Dependencies can be stored in private and final fields • Dagger must create the object • @Provides not required for downstream injection 38
  47. Field Injection • @Inject on fields which are dependencies •

    Field may not be private or final • Injection happens after the object is “alive” 42
  48. Field Injection • @Inject on fields which are dependencies •

    Field may not be private or final • Injection happens after the object is “alive” • Object often must be responsible for injecting itself 42
  49. 44 ObjectGraph og = ObjectGraph.create( new NetworkModule(), new TwitterModule("korovyansk") );

    // Using constructor injection: TweeterApp app = og.get(TweeterApp.class);
  50. 44 ObjectGraph og = ObjectGraph.create( new NetworkModule(), new TwitterModule("korovyansk") );

    // Using constructor injection: TweeterApp app = og.get(TweeterApp.class); // Using field injection: TweeterApp app = new TweeterApp(); og.inject(app);
  51. Android • Entry objects are managed objects constructed by OS


    (impossible to use Constructor injection for OS components) 46
  52. Android • Entry objects are managed objects constructed by OS


    (impossible to use Constructor injection for OS components) • Field injection is Android style
 (including Activities, Fragments, Services, Views) 46
  53. Android • Entry objects are managed objects constructed by OS


    (impossible to use Constructor injection for OS components) • Field injection is Android style
 (including Activities, Fragments, Services, Views) • Application is the best place to keep ObjectGraph 46
  54. Android • Entry objects are managed objects constructed by OS


    (impossible to use Constructor injection for OS components) • Field injection is Android style
 (including Activities, Fragments, Services, Views) • Application is the best place to keep ObjectGraph • Modules and their “injects” segment parts of your app
 using .plus() method 46
  55. 48 public class ExampleApp extends Application { private ObjectGraph objectGraph;

    ! @Override public void onCreate() { super.onCreate(); objectGraph = ObjectGraph.create( new ExampleModule() ); } ! public ObjectGraph getObjectGraph() { return objectGraph; } }
  56. 49 public class ExampleActivity1 extends Activity { @Inject Foo foo;

    @Inject Bar bar; ! @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ! ExampleApp app = (ExampleApp) getApplication(); app.getObjectGraph().inject(this); ! // ... } }
  57. 50 public class ExampleActivityN extends Activity { @Inject Foo foo;

    @Inject Bar bar; ! @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ! ExampleApp app = (ExampleApp) getApplication(); app.getObjectGraph().inject(this); ! // ... } }
  58. 51 @Module( injects = { ExampleActivity1.class, ExampleActivityN.class } ) public

    class ExampleModule { @Provides @Singleton Foo provideFoo() { return new Foo(); } @Provides @Singleton Bar provideBar() { return new Bar(); } }
  59. Android* • Mock mode for parallel and robust development
 (based

    on flavours and overriding of Modules) • Test mode for unit and functional testing
 (based on overriding Modules to follow test scenarios) 52
  60. Android* • Mock mode for parallel and robust development
 (based

    on flavours and overriding of Modules) • Test mode for unit and functional testing
 (based on overriding Modules to follow test scenarios) • Mortar and Flow
 (work with UI with DI in mind) 52
  61. Android Barcamp • August 2, 2014 @ IT-Loft Omsk, starting

    from 14-00 • Fluid program and advanced topics of Android Dev 53
  62. Android Barcamp • August 2, 2014 @ IT-Loft Omsk, starting

    from 14-00 • Fluid program and advanced topics of Android Dev • Take part for FREE! 53
  63. Android Barcamp • August 2, 2014 @ IT-Loft Omsk, starting

    from 14-00 • Fluid program and advanced topics of Android Dev • Take part for FREE! • More details in +Android Developers Omsk 53