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.

Anton Minashkin Dagger 2 light

1,243 views

Published on

Slides for GDG Kyiv Android club meeting #7

Author: Anton Minashkin

Published in: Software
  • Be the first to comment

Anton Minashkin Dagger 2 light

  1. 1. Dagger 2. Right way to do Dependency Injections by Anton Minashkin
  2. 2. Usual JAVA code public class Payroll { ... public long getWithholding(long payInDollars) { ... return withholding; } public long getAfterTaxPay(Employee employee) { long basePay = EmployeeDatabase.getInstance() .getBasePay(employee); long withholding = getWithholding(basePay); return basePay - withholding; } }
  3. 3. Usual JAVA code public class Payroll { ... public long getWithholding(long payInDollars) { ... return withholding; } public long getAfterTaxPay(Employee employee) { long basePay = EmployeeDatabase.getInstance() .getBasePay(employee); long withholding = getWithholding(basePay); return basePay - withholding; } }
  4. 4. Usual JAVA code public class Payroll { ... public long getWithholding(long payInDollars) { ... return withholding; } public long getAfterTaxPay(Employee employee) { long basePay = new EmployeeDatabase() .getBasePay(employee); long withholding = getWithholding(basePay); return basePay - withholding; } }
  5. 5. What is DI? In software engineering, dependency injection is a software design pattern that implements inversion of control for software libraries.
  6. 6. What is DI?
  7. 7. Say “Hi!” to DI public class Payroll { ... EmployeeDatabase mEmployeeDatabase; public Payroll(EmployeeDatabase employeeDatabase) { mEmployeeDatabase = employeeDatabase; } public long getWithholding(long payInDollars) { ... return withholding; } public long getAfterTaxPay(Employee employee) { long basePay = mEmployeeDatabase.getBasePay(employee); long withholding = getWithholding(basePay); return basePay - withholding; } }
  8. 8. Say “Hi!” to DI public class Payroll { ... EmployeeDatabase mEmployeeDatabase; public Payroll(EmployeeDatabase employeeDatabase) { mEmployeeDatabase = employeeDatabase; } public long getWithholding(long payInDollars) { ... return withholding; } public long getAfterTaxPay(Employee employee) { long basePay = mEmployeeDatabase.getBasePay(employee); long withholding = getWithholding(basePay); return basePay - withholding; } }
  9. 9. ...but! Was: new Payroll().getAfterTaxPay(employee); Now: new Payroll(EmployeeDatabase.getInstance()) .getAfterTaxPay(employee);
  10. 10. ...but! Was: new Payroll().getAfterTaxPay(employee); Now: new Payroll(EmployeeDatabase.getInstance()) .getAfterTaxPay(employee);
  11. 11. Java! To the rescue! JSR-330
  12. 12. JSR-330 public class Payroll { ... @Inject public Payroll(EmployeeDatabase employeeDatabase) { mEmployeeDatabase = employeeDatabase; } ... } OR public class Payroll { ... @Inject EmployeeDatabase mEmployeeDatabase; ... }
  13. 13. DI frameworks ● Google Guice ● Spring DI ● Java EE6 CDI ● Dagger ● etc.
  14. 14. DI frameworks ● Google Guice ● Spring DI ● Java EE6 CDI ● Dagger ● etc.
  15. 15. Dagger 2. History Developed by Square Adopted by Google (Dagger 2)
  16. 16. Dagger 2. Main features ● Android friendly ● JSR-330 ● Compile-time DI validation ● Full stack code generation ● User mimic code ● Easy to debug & understand
  17. 17. Dagger 2. API class Thermosiphon implements Pump { private final Heater heater; @Inject Thermosiphon(Heater heater) { this.heater = heater; } ... }
  18. 18. Dagger 2. API class CoffeeMaker { @Inject Heater heater; @Inject Pump pump; ... }
  19. 19. Dagger 2. API @Module class DripCoffeeModule { @Provides Heater provideHeater() { return new ElectricHeater(); } @Provides Pump providePump(Thermosiphon pump) { return pump; } }
  20. 20. Dagger 2. API @Component(modules = DripCoffeeModule.class) interface CoffeeShop { CoffeeMaker maker(); }
  21. 21. Dagger 2. API CoffeeShop coffeeShop = DaggerCoffeeShop.builder() .dripCoffeeModule(new DripCoffeeModule()) .build(); ... CoffeeShop coffeeShop = DaggerCoffeeShop.create();
  22. 22. Dagger 2. API public class CoffeeApp { public static void main(String[] args) { CoffeeShop coffeeShop = DaggerCoffeeShop.create(); coffeeShop.maker().brew(); } }
  23. 23. Dagger 2. Scope @Provides @Singleton Heater provideHeater() { return new ElectricHeater(); }
  24. 24. Dagger 2. Lazy class GridingCoffeeMaker { @Inject Lazy<Grinder> lazyGrinder; public void brew() { while (needsGrinding()) { // Grinder created once on first call to .get() and cached. lazyGrinder.get().grind(); } } }
  25. 25. Dagger 2. Provider Injection class BigCoffeeMaker { @Inject Provider<Filter> filterProvider; public void brew(int numberOfPots) { ... for (int p = 0; p < numberOfPots; p++) { maker.addFilter(filterProvider.get()); //new filter every time. maker.addCoffee(...); maker.percolate(); ... } } }
  26. 26. Dagger 2. Qualifiers @Qualifier @Documented @Retention(RUNTIME) public @interface Named { String value() default ""; }
  27. 27. Dagger 2. Qualifiers class ExpensiveCoffeeMaker { @Inject @Named("water") Heater waterHeater; @Inject @Named("hot plate") Heater hotPlateHeater; ... }
  28. 28. Dagger 2. Qualifiers @Provides @Named("hot plate") Heater provideHotPlateHeater() { return new ElectricHeater(70); } @Provides @Named("water") Heater provideWaterHeater() { return new ElectricHeater(93); }
  29. 29. Dagger 2. Compile-time validation @Module class DripCoffeeModule { @Provides Heater provideHeater(Executor executor) { return new CpuHeater(executor); } } ... [ERROR] COMPILATION ERROR : [ERROR] error: java.util.concurrent.Executor cannot be provided without an @Provides-annotated method.
  30. 30. Dagger 2. Generated code @Override public DataManager get() { DataManager provided = module.provideDataManager(authApiProvider.get(), articleApiProvider.get(), commentsApiProvider.get()); if (provided == null) { throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method"); } return provided; } public static Factory<DataManager> create(DataManagerModule module, Provider<AuthApi> authApiProvider, Provider<ArticleApi> articleApiProvider, Provider<CommentApi> commentApiProvider) { return new DataManagerModule_ProvideDataManagerFactory(module, authApiProvider, articleApiProvider, commentApiProvider); }
  31. 31. Dagger 2. Debugging Here should be example of Guice stacktrace: VERY-VERY-BAD-STACKTRACE And here is Dagger stacktrace: Mmmm… What a lovely stacktrace!
  32. 32. Dagger 2. What should I inject? ● Anything that has constructor parameters ● Anything that is out of local scope ● Infrastructure ● Anything that is shared between >1 objects ● Diferent obj-graphs for diferent flavors
  33. 33. Dagger 2. Where should I inject? public class MyApp extends Application { @Override public void onCreate() { registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { ... @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { inject(activity); } ... }); }
  34. 34. Dagger 2 Example
  35. 35. Dagger 2 Questions?
  36. 36. RTFM! http://google.github.io/dagger/ https://youtu.be/oK_XtfXPkqw anton.minashkin@outlook.com

×