Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

MCE^3 - Gregory Kick - Dagger 2

125 views

Published on

This presentation is an update on Dagger 2. First, we'll give updates on our improvements to the implementation and the features that have been added since our original release. Then we'll discuss some of our plans for some new features and APIs that are coming in the next few months that should make dependency injection in Android applications easier and more straightforward than ever before.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

MCE^3 - Gregory Kick - Dagger 2

  1. 1. Confidential + ProprietaryConfidential + Proprietary Dagger 2 Now Even Pointier!™
  2. 2. Confidential + ProprietaryConfidential + Proprietary An introduction
  3. 3. Confidential + Proprietary A quick (re)introduction to dependency injection /* With Manual DI */ class CoffeeMaker { private final Heater heater; private final Pump pump; CoffeeMaker(Heater heater, Pump pump) { this.heater = checkNotNull(heater); this.pump = checkNotNull(pump); } Coffee makeCoffee() {/* … */} } class CoffeeMain { public static void main(String[] args) { Heater heater = new ElectricHeater(); Pump pump = new Thermosiphon(heater); Coffee coffee = new CoffeeMaker(heater, pump).makeCoffee(); } } /* Without DI */ class CoffeeMaker { private final Heater heater; private final Pump pump; CoffeeMaker() { this.heater = new ElectricHeater(); this.pump = new Thermosiphon(heater); } Coffee makeCoffee() {/* … */} } class CoffeeMain { public static void main(String[] args) { Coffee coffee = new CoffeeMaker().makeCoffee(); } }
  4. 4. Confidential + Proprietary DI with Dagger 2
  5. 5. Confidential + Proprietary Dagger 2 - Injected objects @Inject Thermosiphon(Heater heater) { this.heater = heater; }
  6. 6. Confidential + Proprietary Dagger 2 - declarative configuration @Provides @Singleton Heater provideHeater() { return new ElectricHeater(); }
  7. 7. Confidential + Proprietary Dagger 2 - typesafe dependency injection @Singleton @Component( modules = DripCoffeeModule.class) public interface CoffeeComponent { CoffeeMaker maker(); }
  8. 8. Confidential + Proprietary OK, but why?
  9. 9. Confidential + Proprietary Consistent, efficient instance management
  10. 10. Confidential + Proprietary Dagger 2.0.1 - 2.4
  11. 11. Confidential + ProprietaryConfidential + Proprietary static @Provides methods
  12. 12. Confidential + Proprietary @Provides Heater provideHeater() { return new ElectricHeater(); }
  13. 13. Confidential + Proprietary @Provides static Heater provideHeater() { return new ElectricHeater(); }
  14. 14. Confidential + ProprietaryConfidential + Proprietary Subcomponents
  15. 15. Confidential + Proprietary Subcomponents @Component(modules = {ServerModule.class, AuthModule.class}) interface ServerComponent { Server server(); SessionComponent sessionComponent(SessionModule sessionModule); } @Subcomponent(modules = SessionModule.class) interface SessionComponent { SessionInfo sessionInfo(); RequestComponent requestComponent(); } @Subcomponent(modules = {RequestModule.class, AuthModule.class}) interface RequestComponent { RequestHandler requestHandler(); }
  16. 16. Confidential + ProprietaryConfidential + Proprietary Map Multibindings
  17. 17. Confidential + Proprietary Map multibindings
  18. 18. Confidential + Proprietary enum MessageType { TEXT, PHOTO, LOCATION, } @MapKey @interface ForMessageType { MessageType value(); } Map multibindings @Provides @IntoMap @ForMessageType(TEXT) Renderer contributeTextRenderer() { /*…*/ } @Provides @IntoMap @ForMessageType(PHOTO) Renderer contributePhotoRenderer() { /*…*/ } @Provides @IntoMap @ForMessageType(LOCATION) Renderer contributeVideoRenderer() { /*…*/ }
  19. 19. Confidential + Proprietary Map multibindings @Inject Map<MessageType, Provider<Renderer>> renderers; // … for (Message message : messages) { renderers.get(message.type()).get().render(message); }
  20. 20. Confidential + ProprietaryConfidential + Proprietary Producers
  21. 21. Confidential + Proprietary Producers @ProducerModule(includes = UserModule.class) final class UserResponseModule { @Produces static ListenableFuture<UserData> lookUpUserData( User user, UserDataStub stub) { return stub.lookUpData(user); } @Produces static Html renderHtml( UserData data, UserHtmlTemplate template) { return template.render(data); } } @Module final class ExecutorModule { @Provides @Production static Executor executor() { return Executors.newCachedThreadPool(); } } @ProductionComponent(modules = UserResponseModule.class) interface UserResponseComponent { ListenableFuture<Html> html(); }
  22. 22. Confidential + ProprietaryConfidential + Proprietary Improved error messages
  23. 23. Confidential + Proprietary Error messages error: coffee.Pump cannot be provided without an @Provides-annotated method. CoffeeMaker maker(); ^ coffee.Pump is injected at coffee.CoffeeMaker.<init>(…, pump) coffee.CoffeeMaker is provided at coffee.CoffeeApp.CoffeeComponent.maker()
  24. 24. Confidential + ProprietaryConfidential + Proprietary Project Management
  25. 25. Confidential + Proprietary Development within Google ● Millions of test targets are executed for every Dagger change ● Constant performance testing and monitoring from JVM and Android projects ● New APIs are developed against a huge, searchable repository of real usages ● It is an invaluable, proven model from which we have gotten projects like Guava Working with GitHub ● We haven't done as well as we need to ○ Google builds from HEAD, but the rest of the world doesn't ○ Syncs from Google were big, unmanaged dumps of changes with no compatibility guarantees ● New release policy makes sure that there is a versioned release about every 2 weeks ○ Cultivated change log ○ Compatibility guarantees Project management
  26. 26. Confidential + Proprietary Dagger 2.5+
  27. 27. Confidential + ProprietaryConfidential + Proprietary Performance enhancements
  28. 28. Confidential + Proprietary The generated code
  29. 29. Confidential + Proprietary Unnecessary Providers
  30. 30. Confidential + Proprietary Retained references
  31. 31. Confidential + ProprietaryConfidential + Proprietary @Binds
  32. 32. Confidential + Proprietary @Provides static Pump providePump(Thermosiphon pump) { return pump; }
  33. 33. Confidential + Proprietary @Binds abstract Pump bindPump(Thermosiphon pump);
  34. 34. Confidential + ProprietaryConfidential + Proprietary Memory management tools
  35. 35. Confidential + ProprietaryConfidential + Proprietary Considerations Mobile devices mean we need to be judicious ● Number of allocations ● Long-term memory footprint
  36. 36. Confidential + ProprietaryConfidential + Proprietary Unscoped A new instance for every injection site ● Number of allocations ● Long-term memory footprint
  37. 37. Confidential + ProprietaryConfidential + Proprietary @Scope Only one instance per component ● Number of allocations ● Long-term memory footprint
  38. 38. Confidential + ProprietaryConfidential + Proprietary ● Number of allocations ● Long-term memory footprint @Reusable Instances can be reused, but how and when isn't a functional requirement
  39. 39. Confidential + ProprietaryConfidential + Proprietary Pressure-sensitive scopes There should only be one instance, but if there is memory pressure make it eligible for garbage collection ● Number of allocations ● Long-term memory footprint
  40. 40. Confidential + ProprietaryConfidential + Proprietary Easier subcomponents
  41. 41. Confidential + Proprietary An Application component @Singleton @Component(modules = ApplicationModule.class) interface MyApplicationComponent { MyApplication inject(MyApplication application); @Component.Builder interface Builder { Builder applicationModule(ApplicationModule module); MyApplicationComponent build(); } }
  42. 42. Confidential + Proprietary @ActivityScoped @Subcomponent( modules = ActivityModule.class) interface MainActivitySubcomponent { MainActivity injectMainActivity( MainActivity activity); @Subcomponent.Builder interface Builder { Builder activityModule( ActivityModule activityModule); MainActivitySubcomponent build(); } } An activity subcomponent today @Singleton @Component(modules = ApplicationModule. class) interface MyApplicationComponent { MyApplication inject( MyApplication application); MainActivitySubcomponent.Builder newMainActivitySubcomponentBuilder(); /* … */ }
  43. 43. Confidential + Proprietary What if we didn't have to have that method? public final class MyAppication extends Application { @Inject MainActivitySubcomponent.Builder builder; /* … */ }
  44. 44. Confidential + Proprietary First, a common interface interface ActivityComponentBuilder<A extends Activity> { ActivityComponentBuilder<A> activityModule(ActivityModule activityModule); MembersInjector<A> build(); } @ActivityScoped @Subcomponent(modules = ActivityModule.class) interface MainActivitySubcomponent { MainActivity injectMainActivity(MainActivity activity); @Subcomponent.Builder interface Builder extends ActivityComponentBuilder<ActivityModule> {} }
  45. 45. Confidential + Proprietary Second, map multibinder @Module abstract class MainActivitySubcomponentModule { @Binds @IntoMap @ActivityKey(MainActivity.class) abstract ActivityComponentBuilder<?> bindBuilder( MainActivitySubcomponent.Builder<MainActivity> impl); }
  46. 46. Confidential + Proprietary Finally, back to MyApplication interface HasActivitySubcomponentBuilders { <A extends Activity> ActivityComponentBuilder<A> getActivityComponentBuilder( Class<? extends Activity> activityClass); } class MyApplication extends Application implements HasActivitySubcomponentBuilders { @Inject Map<Class<? extends Activity, ActivityComponentBuilder<?>> activityComponentBuilders; @Override public <A extends Activity> ActivityComponentBuilder<A> getActivityComponentBuilder( Class<? extends Activity> activityClass) { checkArgument(activityComponentBuilders.containsKey(activityClass)); return (ActivityComponentBuilder<A>) activityComponentBuilders.get(activityClass); } }
  47. 47. Confidential + Proprietary Q & A

×