Dagger by Square


Dependency Injection for Android



Laurynas Veržukauskas
@im0rtality

2014


DAGger




  • Directed
  • Acyclic
  • Graph

DEPENDENCY INJECTION





  • Decoupling
  • Uniformity







WHY?

  • Works on Android!
  • Fast 
    • Dagger - generates code up-front, 
    • Guice - uses Reflection
  • Optional compiler plugin can flag various errors at compile time:
    • Detect cyclic dependencies
    • Detect unused and duplicate bindings
    • Detect incomplete modules
  • Simple (but limited) API compared to Guice
  • Uses standard annotations where possible (javax.inject.*)

USING DAGGER 1/3


dependencies {
    compile 'com.squareup.dagger:dagger:1.2.1'
    
    ...
} 

USING DAGGER 2/3

class Thermosiphon implements Pump {
    private final Heater heater;
    
    @Inject
    Thermosiphon(Heater heater) {
        this.heater = heater;
    }
    ...
}
class CoffeeMaker {
  @Inject Heater heater;
  @Inject Pump pump;
  ...
} 
@Module
class DripCoffeeModule {
  @Provides Heater provideHeater() {
    return new ElectricHeater();
  }
}

USING DAGGER 3/3


public static void main(String[] args) {
   ObjectGraph og = ObjectGraph.create(new DripCoffeeModule());
// og.plus(new AnotherCoffeeModule); CoffeeApp coffeeApp = og.get(CoffeeApp.class);   coffeeApp.brew(); }

@Singleton

Single instance of the value for all of its clients

@Provides @Singleton Heater provideHeater() {
  return new ElectricHeater();
} 


@Singleton
class CoffeeMaker {
  ...
} 

Provider<T>


Provider<T> creates a new instance of T each time .get() is called

class BigCoffeeMaker {
  @Inject Provider<Filter> filterProvider;

  public void brew(int numberOfPots) {
    ...
    for (int p = 0; p < numberOfPots; p++) {      //new filter every time.
      maker.addFilter(filterProvider.get()); 
      maker.addCoffee(...);
      ...
    }
  }
} 

@Named("foo")


class ExpensiveCoffeeMaker {
  @Inject @Named("water") Heater waterHeater;
  @Inject @Named("hot plate") Heater hotPlateHeater;
  ...
}


@Provides @Named("hot plate") Heater provideHotPlateHeater() {
  return new ElectricHeater(70);
}

@Provides @Named("water") Heater provideWaterHeater() {
  return new ElectricHeater(93);
}


Lazy<T>


class GridingCoffeeMaker {
 @Inject Lazy<Grinder> lazyGrinder;

 public void brew() {
   while (needsGrinding()) {
    // Grinder created once on first call to .get() and cached.
    lazyGrinder.get().grind();
   }
 }
} 

@Inject @Singleton Lazy<Foo> foo; // ??? 

COMPILE-TIME CHECKING


[ERROR]: Graph validation failed: You have these unused @Provider methods:
      1. coffee.DripCoffeeModule.provideChiller()



  1. Checks your dependencies
  2. Generates DI classes for debugging
  3. Generates DI graph representation (Graphviz)

WHERE IT FALLS SHORT

  • Injectable objects MUST have @Inject constructor
  • Can't inject constructors that throw exceptions
  • Can't inject methods
  • Some boilerplate code

    CONCLUSION

    • awesome
      • detecting dependency problems at compile time 
      • simple api
    • not so much
      • noticeable performance only on older devices
      • some quirks




    QUESTIONS?




    https://github.com/square/dagger

    Dagger

    By Laurynas Veržukauskas

    Dagger

    Dependency Injection for Android

    • 787