1. Dagger 2. Right way to do
Dependency Injections
by Anton Minashkin
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. 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. 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. What is DI?
In software engineering, dependency
injection is a software design pattern that
implements inversion of control for software
libraries.
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. 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;
}
}
12. JSR-330
public class Payroll {
...
@Inject
public Payroll(EmployeeDatabase employeeDatabase) {
mEmployeeDatabase = employeeDatabase;
}
...
}
OR
public class Payroll {
...
@Inject
EmployeeDatabase mEmployeeDatabase;
...
}
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. Dagger 2. API
class Thermosiphon implements Pump {
private final Heater heater;
@Inject
Thermosiphon(Heater heater) {
this.heater = heater;
}
...
}
18. Dagger 2. API
class CoffeeMaker {
@Inject Heater heater;
@Inject Pump pump;
...
}
19. Dagger 2. API
@Module
class DripCoffeeModule {
@Provides Heater provideHeater() {
return new ElectricHeater();
}
@Provides Pump providePump(Thermosiphon pump) {
return pump;
}
}
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. 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();
...
}
}
}
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. 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. 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. 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. 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);
}
...
});
}