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

Optimizing Dagger on Android

E097aa898a62cea7f5a9ddf9b3d8615c?s=47 Ron Shapiro
September 26, 2017

Optimizing Dagger on Android

We'll discuss recent developments in Dagger for Android, both in terms of new APIs in dagger.android and optimizations in generated code. We'll then discuss how to not encounter common pitfalls that decrease runtime performance.

E097aa898a62cea7f5a9ddf9b3d8615c?s=128

Ron Shapiro

September 26, 2017
Tweet

Transcript

  1. Optimizing Dagger on Android Ron Shapiro ronsh@google @rdshapiro

  2. Prereqs

  3. Prereqs • You've used Dagger before

  4. Prereqs • You've used Dagger before • Optional: Understanding Dagger

    2's Generated Code ◦ https://goo.gl/toV6Nq
  5. Prereqs • You've used Dagger before • Optional: Understanding Dagger

    2's Generated Code ◦ https://goo.gl/toV6Nq • You’re not scared to look at generated code
  6. Glossary

  7. Glossary • Key ! Type + Optional<Qualifier>

  8. Glossary • Key ! Type + Optional<Qualifier> • Binding !

    Key + ImmutableSet<DependencyRequest>
  9. Glossary • Key ! Type + Optional<Qualifier> • Binding !

    Key + ImmutableSet<DependencyRequest> @Provides
 Airplane airplane(
  10. Glossary • Key ! Type + Optional<Qualifier> • Binding !

    Key + ImmutableSet<DependencyRequest> @Provides
 Airplane airplane( Body body, @Left Wing left, @Right Wing right) { … }
  11. Glossary • Key ! Type + Optional<Qualifier> • Binding !

    Key + ImmutableSet<DependencyRequest> @Provides
 Airplane airplane( Body body, @Left Wing left, @Right Wing right) { … } • DependencyRequest ! Key + Kind
  12. Glossary • Key ! Type + Optional<Qualifier> • Binding !

    Key + ImmutableSet<DependencyRequest> @Provides
 Airplane airplane( Body body, @Left Wing left, @Right Wing right) { … } • DependencyRequest ! Key + Kind ◦ enum Kind { INSTANCE, PROVIDER, LAZY, … }
  13. Glossary • Key ! (normalized) Type + Optional<Qualifier> • Binding

    ! Key + ImmutableSet<DependencyRequest> @Provides
 Airplane airplane( Body body, @Left Wing left, @Right Wing right) { … }1 • DependencyRequest ! Key + Kind ◦ enum Kind { INSTANCE, PROVIDER, LAZY, … }
  14. Glossary • Key ! (normalized) Type + Optional<Qualifier> • Binding

    ! Key + ImmutableSet<DependencyRequest> @Provides
 Airplane airplane( Body body, @Left Wing left, @Right Wing right) { … }1 
 @Provides
 XWing xWing( Body body, @Left Wing left, @Right Wing right) { … } • DependencyRequest ! Key + Kind ◦ enum Kind { INSTANCE, PROVIDER, LAZY, … }
  15. Glossary • Key ! (normalized) Type + Optional<Qualifier> • Binding

    ! Key + ImmutableSet<DependencyRequest> @Provides
 Airplane airplane( Body body, @Left Wing left, @Right Wing right) { … }1 
 @Provides
 XWing xWing( Body body, @Left Provider<Wing> left, @Right Provider<Wing> right) { … } • DependencyRequest ! Key + Kind ◦ enum Kind { INSTANCE, PROVIDER, LAZY, … }
  16. Glossary • Key ! (normalized) Type + Optional<Qualifier> • Binding

    ! Key + ImmutableSet<DependencyRequest> @Provides
 Airplane airplane( Body body, @Left Wing left, @Right Wing right) { … }1 
 @Provides
 XWing xWing( Body body, @Left Provider<Wing> left, @Right Provider<Wing> right, Logo logo) { … } • DependencyRequest ! Key + Kind ◦ enum Kind { INSTANCE, PROVIDER, LAZY, … }
  17. Glossary • Key ! (normalized) Type + Optional<Qualifier> • Binding

    ! Key + ImmutableSet<DependencyRequest> @Provides
 Airplane airplane( Body body, @Left Wing left, @Right Wing right) { … }1 
 @Provides
 XWing xWing( Body body, @Left Provider<Wing> left, @Right Provider<Wing> right, Lazy<Logo> logo) { … } • DependencyRequest ! Key + Kind ◦ enum Kind { INSTANCE, PROVIDER, LAZY, … }
  18. Life of a DependencyRequest java/dagger/internal/codegen/BindingExpression.java

  19. Life of a DependencyRequest • How many bindings have this

    key? java/dagger/internal/codegen/BindingExpression.java
  20. Life of a DependencyRequest • How many bindings have this

    key? ◦ 0 ! missing binding error java/dagger/internal/codegen/BindingExpression.java
  21. Life of a DependencyRequest • How many bindings have this

    key? ◦ 0 ! missing binding error ◦ 2+ ! duplicate binding error java/dagger/internal/codegen/BindingExpression.java
  22. Life of a DependencyRequest • How many bindings have this

    key? ◦ 0 ! missing binding error ◦ 2+ ! duplicate binding error java/dagger/internal/codegen/BindingExpression.java
  23. Life of a DependencyRequest • How many bindings have this

    key? ◦ 0 ! missing binding error ◦ 2+ ! duplicate binding error • How can Binding X be represented as DependencyRequest.Kind Y using X's own dependencies? java/dagger/internal/codegen/BindingExpression.java
  24. @Module class AirplaneModule { @Provides Airplane weldAndCreate() {}1 }2 Life

    of a DependencyRequest java/dagger/internal/codegen/SimpleMethodBindingExpression.java
  25. @Module class AirplaneModule { @Provides Airplane weldAndCreate(Body body) {}1 }2

    Life of a DependencyRequest java/dagger/internal/codegen/SimpleMethodBindingExpression.java
  26. @Module class AirplaneModule { @Provides Airplane weldAndCreate( Body body, @Left

    Wing leftWing, @Right Wing rightWing) {}1 }2 Life of a DependencyRequest java/dagger/internal/codegen/SimpleMethodBindingExpression.java
  27. @Module class AirplaneModule { @Provides Airplane weldAndCreate( Body body, @Left

    Wing leftWing, @Right Wing rightWing, Welder welder) {}1 }2 Life of a DependencyRequest java/dagger/internal/codegen/SimpleMethodBindingExpression.java
  28. @Module class AirplaneModule { @Provides Airplane weldAndCreate( Body body, @Left

    Wing leftWing, @Right Wing rightWing, Welder welder, Lazy<SafetyFeature> lazySafety) {}1 }2 Life of a DependencyRequest java/dagger/internal/codegen/SimpleMethodBindingExpression.java
  29. @Module class AirplaneModule { @Provides Airplane weldAndCreate( Body body, @Left

    Wing leftWing, @Right Wing rightWing, Welder welder, Lazy<SafetyFeature> lazySafety) { welder.weld(body, leftWing); welder.weld(body, rightWing); if (LAWYERS_REQUIRE_SAFETY_FEATURE) { lazySafety.get().protect(body); } return new Airplane(body); }1 }2 Life of a DependencyRequest java/dagger/internal/codegen/SimpleMethodBindingExpression.java
  30. Life of a DependencyRequest @Component(modules = { AirplaneModule.class, WingModule.class, })

    interface AirplaneComponent { Airplane createAirplane(); }
  31. Life of a DependencyRequest @Override Airplane createAirplane() { airplaneModule.weldAndCreate( 1/*

    body */,2 1/* left wing */, 1/* right wing */, 1/* welder */, 1/* safety feature */); } java/dagger/internal/codegen/SimpleMethodBindingExpression.java
  32. Life of a DependencyRequest @Override Airplane createAirplane() { airplaneModule.weldAndCreate( 1new

    Body(),2 1/* left wing */, 1/* right wing */, 1/* welder */, 1/* safety feature */); } java/dagger/internal/codegen/SimpleMethodBindingExpression.java
  33. Life of a DependencyRequest @Override Airplane createAirplane() { airplaneModule.weldAndCreate( 1new

    Body(new Steel()),2 1/* left wing */, 1/* right wing */, 1/* welder */, 1/* safety feature */); } java/dagger/internal/codegen/SimpleMethodBindingExpression.java
  34. Life of a DependencyRequest @Override Airplane createAirplane() { airplaneModule.weldAndCreate( 1new

    Body(new Steel()),2 1WingModule.createLeftWing(new Steel()), 1/* right wing */, 1/* welder */, 1/* safety feature */); } java/dagger/internal/codegen/SimpleMethodBindingExpression.java
  35. Life of a DependencyRequest @Override Airplane createAirplane() { airplaneModule.weldAndCreate( 1new

    Body(new Steel()),2 1WingModule.createLeftWing(new Steel()), 1WingModule.createRightWing(new Steel(), new Logo()), 1/* welder */, 1/* safety feature */); } java/dagger/internal/codegen/SimpleMethodBindingExpression.java
  36. Life of a DependencyRequest @Override Airplane createAirplane() { airplaneModule.weldAndCreate( 1new

    Body(new Steel()),2 1WingModule.createLeftWing(new Steel()), 1WingModule.createRightWing(new Steel(), new Logo()), 1welderProvider.get(), 1/* safety feature */); } java/dagger/internal/codegen/SimpleMethodBindingExpression.java java/dagger/internal/codegen/FrameworkType.java
  37. Life of a DependencyRequest @Override Airplane createAirplane() { airplaneModule.weldAndCreate( 1new

    Body(new Steel()),2 1WingModule.createLeftWing(new Steel()), 1WingModule.createRightWing(new Steel(), new Logo()), 1welderProvider.get() /* */, 1/* safety feature */); } java/dagger/internal/codegen/SimpleMethodBindingExpression.java java/dagger/internal/codegen/FrameworkType.java
  38. Life of a DependencyRequest @Override Airplane createAirplane() { airplaneModule.weldAndCreate( 1new

    Body(new Steel()),2 1WingModule.createLeftWing(new Steel()), 1WingModule.createRightWing(new Steel(), new Logo()), 1welderProvider.get() /* */, 1DoubleCheck.lazy(safetyProvider); } java/dagger/internal/codegen/SimpleMethodBindingExpression.java java/dagger/internal/codegen/FrameworkType.java
  39. Life of a DependencyRequest @Override Airplane createAirplane() { airplaneModule.weldAndCreate( 1new

    Body(new Steel()),2 1WingModule.createLeftWing(new Steel()), 1WingModule.createRightWing(new Steel(), new Logo()), 1welderProvider.get() /* */, 1DoubleCheck.lazy(safetyProvider /* */); } java/dagger/internal/codegen/SimpleMethodBindingExpression.java java/dagger/internal/codegen/FrameworkType.java
  40. Life of a component initialization private void initialize() { this.welderProvider

    =1 }2 java/dagger/internal/codegen/FrameworkFieldInitializer.java
  41. Life of a component initialization private void initialize() { this.welderProvider

    =1 new Provider<Welder>() { @Override public Welder get()3{}4 }; }2 java/dagger/internal/codegen/FrameworkFieldInitializer.java
  42. Life of a component initialization private void initialize() { this.welderProvider

    =15 6new Provider<Welder>() { @Override public Welder get()3{ return new Welder( new Wire(), new ProtectiveShield(), flamethrowerProvider.get()); }4 }; }2 java/dagger/internal/codegen/FrameworkFieldInitializer.java
  43. Life of a component initialization private void initialize() { this.welderProvider

    =1DoubleCheck.provider(5 6new Provider<Welder>() { @Override public Welder get()3{ return new Welder( new Wire(), new ProtectiveShield(), flamethrowerProvider.get()); }4 }); }2 java/dagger/internal/codegen/FrameworkFieldInitializer.java
  44. Life of a component initialization private void initialize() { this.welderProvider

    =1DoubleCheck.provider(5 6new Provider<Welder>() { ^ error: [MemoryLeak] this might leak your *entire* component! @Override public Welder get()3{ return new Welder( new Wire(), new ProtectiveShield(), flamethrowerProvider.get()); }4 }); }2 java/dagger/internal/codegen/FrameworkFieldInitializer.java ^ shameless plug for ErrorProne github.com/google/error-prone
  45. Life of a component initialization java/dagger/internal/codegen/FrameworkFieldInitializer.java

  46. Life of a component initialization private void initialize() { java/dagger/internal/codegen/FrameworkFieldInitializer.java

  47. Life of a component initialization private void initialize() { this.wireProvider

    = Wire_Factory.create(); java/dagger/internal/codegen/FrameworkFieldInitializer.java
  48. Life of a component initialization private void initialize() { this.wireProvider

    = Wire_Factory.create(); this.protectiveShieldProvider =
 ProtectiveShield_Factory.create(); java/dagger/internal/codegen/FrameworkFieldInitializer.java
  49. Life of a component initialization private void initialize() { this.wireProvider

    = Wire_Factory.create(); this.protectiveShieldProvider =
 ProtectiveShield_Factory.create(); this.welderProvider = DoubleChecker.provider(
 Welder_Factory.create(
 wireProvider,
 protectiveShieldProvider,
 flamethrowerProvider)); java/dagger/internal/codegen/FrameworkFieldInitializer.java
  50. Life of a component initialization private void initialize() { this.wireProvider

    = Wire_Factory.create(); this.protectiveShieldProvider =
 ProtectiveShield_Factory.create(); this.welderProvider = DoubleChecker.provider(
 Welder_Factory.create(
 wireProvider,
 protectiveShieldProvider,
 flamethrowerProvider)); } java/dagger/internal/codegen/FrameworkFieldInitializer.java
  51. Why does this matter?

  52. tl;dr: component initialization is

  53. tl;dr: component initialization is s l o w

  54. But just how slow is it? Activity component measurements initialization

    time
  55. But just how slow is it? 200ms Activity component measurements

    initialization time init #1
  56. But just how slow is it? 200ms 2 ms Activity

    component measurements initialization time init #1 init #2+
  57. But just how slow is it? 200ms 2 ms 102!

    Activity component measurements initialization time init #1 init #2+
  58. But just how slow is it? 200ms 2 ms 102!

    Activity component measurements initialization time What is happening here? init #1 init #2+
  59. But just how slow is it? 200ms 2 ms 102!

    Activity component measurements initialization time What is happening here? Answer: class loading init #1 init #2+
  60. How can we load fewer classes?

  61. How can we load fewer classes? • com.google.dagger:dagger-compiler:2.12

  62. How can we load fewer classes? • com.google.dagger:dagger-compiler:2.12 ◦ coming

    very soon!
  63. Dagger 2.12 Bindings Provider form Inlined form java/dagger/internal/codegen/SetBindingExpression.java

  64. Dagger 2.12 Bindings Provider form Inlined form @Provides @IntoSet T

    single() { … } @Provides @ElementsIntoSet Set<T> many() { … } java/dagger/internal/codegen/SetBindingExpression.java
  65. Dagger 2.12 Bindings Provider form Inlined form @Provides @IntoSet T

    single() { … } @Provides @ElementsIntoSet Set<T> many() { … } SetFactory.builder() .add(Single_Factory.create()) .addAll(Many_Factory.create()) .build(); java/dagger/internal/codegen/SetBindingExpression.java
  66. Dagger 2.12 Bindings Provider form Inlined form @Provides @IntoSet T

    single() { … } @Provides @ElementsIntoSet Set<T> many() { … } SetFactory.builder() .add(Single_Factory.create()) .addAll(Many_Factory.create()) .build(); ImmutableSet.builder() .add(single()) .addAll(many()) .build(); java/dagger/internal/codegen/SetBindingExpression.java
  67. Dagger 2.12 Bindings Provider form Inlined form java/dagger/internal/codegen/MapBindingExpression.java

  68. Dagger 2.12 Bindings Provider form Inlined form @Provides @IntoMap @IntKey(1)

    V first() { … } @Provides @IntoMap @IntKey(2) V second() { … } java/dagger/internal/codegen/MapBindingExpression.java
  69. Dagger 2.12 Bindings Provider form Inlined form @Provides @IntoMap @IntKey(1)

    V first() { … } @Provides @IntoMap @IntKey(2) V second() { … } MapFactory.builder() .put(1, First_Factory.create()) .put(2, Second_Factory.create()) .build(); java/dagger/internal/codegen/MapBindingExpression.java
  70. Dagger 2.12 Bindings Provider form Inlined form @Provides @IntoMap @IntKey(1)

    V first() { … } @Provides @IntoMap @IntKey(2) V second() { … } MapFactory.builder() .put(1, First_Factory.create()) .put(2, Second_Factory.create()) .build(); ImmutableMap.builder() .put(1, first()) .put(2, second()) .build(); java/dagger/internal/codegen/MapBindingExpression.java
  71. Dagger 2.12 Bindings Provider form Inlined form java/dagger/internal/codegen/OptionalBindingExpression.java

  72. Dagger 2.12 Bindings Provider form Inlined form @BindsOptionalOf DebugLogger sometimes();

    java/dagger/internal/codegen/OptionalBindingExpression.java
  73. Dagger 2.12 Bindings Provider form Inlined form @BindsOptionalOf DebugLogger sometimes();

    new Provider<Optional<DebugLogger>>() { @Override public Optional<DebugLogger> get() { return Optional.of(debugLoggerProvider.get()); } } java/dagger/internal/codegen/OptionalBindingExpression.java
  74. Dagger 2.12 Bindings Provider form Inlined form @BindsOptionalOf DebugLogger sometimes();

    new Provider<Optional<DebugLogger>>() { @Override public Optional<DebugLogger> get() { return Optional.of(debugLoggerProvider.get()); } } Optional.of(DebugModule.logger()); java/dagger/internal/codegen/OptionalBindingExpression.java
  75. Dagger 2.12 Bindings Provider form Inlined form java/dagger/internal/codegen/ComponentProvisionBindingExpression.java

  76. Dagger 2.12 Bindings Provider form Inlined form @Component @Component( interface

    DatabaseComponent { dependencies = DatabaseComponent.class) Database database(); interface NetworkingComponent { } UsesDatabase usesDatabase(); } java/dagger/internal/codegen/ComponentProvisionBindingExpression.java
  77. Dagger 2.12 Bindings Provider form Inlined form @Component @Component( interface

    DatabaseComponent { dependencies = DatabaseComponent.class) Database database(); interface NetworkingComponent { } UsesDatabase usesDatabase(); } new Provider<Database>() { @Override public Database get() { return databaseComponent.database(); } }; java/dagger/internal/codegen/ComponentProvisionBindingExpression.java
  78. Dagger 2.12 Bindings Provider form Inlined form @Component @Component( interface

    DatabaseComponent { dependencies = DatabaseComponent.class) Database database(); interface NetworkingComponent { } UsesDatabase usesDatabase(); } new Provider<Database>() { @Override public Database get() { return databaseComponent.database(); } }; databaseComponent.database(); java/dagger/internal/codegen/ComponentProvisionBindingExpression.java
  79. How can we load fewer classes? • com.google.dagger:dagger-compiler:2.12 ◦ coming

    very soon!
  80. How can we load fewer classes? • com.google.dagger:dagger-compiler:2.12 ◦ coming

    very soon! • Unnecessary Provider/Lazy usage
  81. Don't force Dagger's hand public class DroidconScheduleActivity extends Activity {

    @Inject Provider<Schedule> scheduleProvider; @Override public void onCreate() { scheduleView.setSchedule(scheduleProvider.get()); } }
  82. Don't force Dagger's hand

  83. Don't force Dagger's hand If you inject…

  84. Don't force Dagger's hand If you inject… || Provider<YourBinding>

  85. Don't force Dagger's hand If you inject… || Provider<YourBinding> ||

    Lazy<YourBinding>
  86. Don't force Dagger's hand If you inject… || Provider<YourBinding> ||

    Lazy<YourBinding>
  87. Don't force Dagger's hand If you inject… || Provider<YourBinding> ||

    Lazy<YourBinding> And
  88. Don't force Dagger's hand If you inject… || Provider<YourBinding> ||

    Lazy<YourBinding> And || you always call get() exactly once (especially in the constructor / onCreate())
  89. Don't force Dagger's hand If you inject… || Provider<YourBinding> ||

    Lazy<YourBinding> And || you always call get() exactly once (especially in the constructor / onCreate()) || YourBinding is not expensive to create, but you aren't sure if you need it
  90. Don't force Dagger's hand If you inject… || Provider<YourBinding> ||

    Lazy<YourBinding> And || you always call get() exactly once (especially in the constructor / onCreate()) || YourBinding is not expensive to create, but you aren't sure if you need it
  91. Don't force Dagger's hand If you inject… || Provider<YourBinding> ||

    Lazy<YourBinding> And || you always call get() exactly once (especially in the constructor / onCreate()) || YourBinding is not expensive to create, but you aren't sure if you need it Instead
  92. Don't force Dagger's hand If you inject… || Provider<YourBinding> ||

    Lazy<YourBinding> And || you always call get() exactly once (especially in the constructor / onCreate()) || YourBinding is not expensive to create, but you aren't sure if you need it Instead && Simply inject YourBinding with no wrapper type
  93. Don't force Dagger's hand If you inject… || Provider<YourBinding> ||

    Lazy<YourBinding> And || you always call get() exactly once (especially in the constructor / onCreate()) || YourBinding is not expensive to create, but you aren't sure if you need it Instead && Simply inject YourBinding with no wrapper type && Profile your code!
  94. Don't force Dagger's hand public class DroidconScheduleActivity extends Activity {

    @Inject Lazy<Schedule> lazySchedule; @Override public void onCreate() { scheduleView.setSchedule(lazySchedule.get()); }1 }2
  95. Don't force Dagger's hand public class DroidconScheduleActivity extends Activity {

    @Inject Lazy<Schedule> lazySchedule; @Inject Lazy<Schedule> lazySchedule2; @Override public void onCreate() { scheduleView.setSchedule(lazySchedule.get()); }1 }2
  96. Don't force Dagger's hand public class DroidconScheduleActivity extends Activity {

    @Inject Lazy<Schedule> lazySchedule; @Inject Lazy<Schedule> lazySchedule2; @Override public void onCreate() { assertThat(lazySchedule.get()); }1 }2
  97. Don't force Dagger's hand public class DroidconScheduleActivity extends Activity {

    @Inject Lazy<Schedule> lazySchedule; @Inject Lazy<Schedule> lazySchedule2; @Override public void onCreate() { assertThat(lazySchedule.get()) .isNotSameAs(lazySchedule2.get()); }1 }2
  98. Don't force Dagger's hand @Inject Provider<YourBinding> myProvider; YourBinding[] array =

    new YourBinding[4]; for (i = 0; i < 4; i++) { array[i] = myProvider.get();2 }1
  99. Don't force Dagger's hand @Inject Provider<YourBinding> myProvider; @Inject<YourBinding>yb0; @Inject<YourBinding>yb1; @Inject<YourBinding>yb2;

    @Inject<YourBinding>yb3; YourBinding[] array = new YourBinding[4]; for (i = 0; i < 4; i++) { array[i] = myProvider.get();2 }1
  100. Don't force Dagger's hand @Inject Provider<YourBinding> myProvider; @Inject<YourBinding>yb0; @Inject<YourBinding>yb1; @Inject<YourBinding>yb2;

    @Inject<YourBinding>yb3; YourBinding[] array = {yb0, yb1, yb2, yb3};
  101. Don't force Dagger's hand @Inject<YourBinding>yb0; @Inject<YourBinding>yb1; @Inject<YourBinding>yb2; @Inject<YourBinding>yb3; YourBinding[] array

    = {yb0, yb1, yb2, yb3};
  102. How can we load fewer classes? • com.google.dagger:dagger-compiler:2.12 ◦ coming

    very soon! • Unnecessary Provider/Lazy usage
  103. How can we load fewer classes? • com.google.dagger:dagger-compiler:2.12 ◦ coming

    very soon! • Unnecessary Provider/Lazy usage • Reconsider scoping decisions
  104. Reconsider scoping

  105. Reconsider scoping @AnalyticsScope
 class AnalyticsTracker {

  106. Reconsider scoping @AnalyticsScope
 class AnalyticsTracker { @Inject AnalyticsTracker(
 UnsyncedAnalyticsQueue queue,


    String flowName,
 ViewToAnalyticsIdTranslator viewTranslator) { … }
  107. Reconsider scoping @AnalyticsScope
 class AnalyticsTracker { @Inject AnalyticsTracker(
 UnsyncedAnalyticsQueue queue,


    String flowName,
 ViewToAnalyticsIdTranslator viewTranslator) { … } 
 void trackClick(View view) {
 queue.add(flowName, viewTranslator.translate(view)); }
  108. Reconsider scoping @AnalyticsScope
 class AnalyticsTracker { @Inject AnalyticsTracker(
 UnsyncedAnalyticsQueue queue,


    String flowName,
 ViewToAnalyticsIdTranslator viewTranslator) { … } 
 void trackClick(View view) {
 queue.add(flowName, viewTranslator.translate(view)); } 
 void onDetach() { queue.sendAnalyticsToServer(); }
 }A
  109. Reconsider scoping @AnalyticsScope class AnalyticsTracker { @Inject AnalyticsTracker( UnsyncedAnalyticsQueue queue,

    String flowName, ViewToAnalyticsIdTranslator viewTranslator) { … } }A
  110. Reconsider scoping @AnalyticsScope class AnalyticsTracker { @Inject AnalyticsTracker( UnsyncedAnalyticsQueue queue,

    String flowName, ViewToAnalyticsIdTranslator viewTranslator) { … } }A class UnsyncedAnalyticsQueue {}
  111. Reconsider scoping class AnalyticsTracker { @Inject AnalyticsTracker( UnsyncedAnalyticsQueue queue, String

    flowName, ViewToAnalyticsIdTranslator viewTranslator) { … } }A @AnalyticsScope class UnsyncedAnalyticsQueue {}
  112. Reconsider scoping @Singleton @Component(modules = ExecutorModule.class) interface NetworkingComponent {Q…Z} @Module

    abstract class ExecutorModule { @Provides @Singleton @Background Executor provideBackgroundExecutor() { return Executors.newCachedThreadPool(4); } }
  113. Reconsider scoping @Singleton @Component(modules = ExecutorModule.class) interface NetworkingComponent { Q//

    …Z }R
  114. Reconsider scoping @Singleton @Component interface NetworkingComponent { // …Z 1

    }R2
  115. Reconsider scoping @Singleton @Component interface NetworkingComponent { // … 1@Component.Builder

    interface Builder { @BindsInstance Builder executor(Executor e); NetworkingComponent build(); } }R
  116. How can we load fewer classes? • com.google.dagger:dagger-compiler:2.12 ◦ coming

    very soon! • Unnecessary Provider/Lazy usage • Reconsider scoping decisions
  117. How can we load fewer classes? • com.google.dagger:dagger-compiler:2.12 ◦ coming

    very soon! • Unnecessary Provider/Lazy usage • Reconsider scoping decisions • Suggest better codegen strategies ◦ github.com/google/dagger/issues
  118. Dagger on Android Stop making me think about injection

  119. Dagger on Android public class LoginActivity extends Activity { @Inject

    OAuthClient oauth; @Inject PasswordEncrypter encrypter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ((DroidconApp) getApplication()) .getComponent() .inject(this); } }
  120. Dagger on Android public class DroidconApp extends Application { private

    DroidconComponent component; public DroidconComponent getComponent() { if (component == null) { component = DaggerDroidconComponent.create(); } return component; } }
  121. dagger.android public class LoginActivity extends DaggerActivity { @Inject OAuthClient oauth;

    @Inject PasswordEncrypter encrypter; } public class DroidconApp extends DaggerApplication {} @Module interface LoginModule { @ContributesAndroidInjector LoginActivity configureLoginActivityInjection(); }
  122. dagger.android • DaggerActivity • DaggerFragment • DaggerService + DaggerIntentService •

    DaggerBroadcastReceiver • DaggerApplication • DaggerAppCompatActivity • dagger.android.support.DaggerFragment • @ContributesAndroidInjector
  123. dagger.android under the hood @ContributesAndroidInjector(modules = LoginSpecificModule.class) LoginActivity loginActivity(); @Subcomponent(modules

    = LoginSpecificModule.class) interface LoginActivitySubcomponent extends AndroidInjector<LoginActivity> { @Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<LoginActivity> {} }
  124. Faster builds w/ Dagger

  125. Compile as little as possible • When you have a

    hammer, everything looks like a @Subcomponent ◦ but subcomponents require compilation at the root! • Break up compilation where possible ◦ gradle users: make lots of modules ◦ bazel users: split up java_librarys
  126. Compile as little as possible

  127. Compile as little as possible @Component(modules = NetworkingModule.class)
 interface NetworkingComponent

    {
 OkHttpClient httpClient();
 }
  128. Compile as little as possible @Component(modules = NetworkingModule.class)
 interface NetworkingComponent

    {
 OkHttpClient httpClient();
 }
  129. Compile as little as possible @Component(modules = NetworkingModule.class)
 interface NetworkingComponent

    {
 OkHttpClient httpClient();
 } 
 @Component(dependencies = NetworkingComponent.class)
 interface AppComponent {
 ApiService apiService();
 }
  130. Compile as little as possible @Component(modules = NetworkingModule.class)
 interface NetworkingComponent

    {
 OkHttpClient httpClient();
 } 
 @Component(dependencies = NetworkingComponent.class)
 interface AppComponent {
 ApiService apiService();
 }
  131. Compile as little as possible @Component(modules = NetworkingModule.class)
 interface NetworkingComponent

    {
 OkHttpClient httpClient();
 } 
 @Component(dependencies = NetworkingComponent.class)
 interface AppComponent {
 ApiService apiService();
 } class ApiService {
 @Inject ApiService(OkHttpClient httpClient) { … }
 }
  132. Compile as little as possible @Component(modules = NetworkingModule.class)
 interface NetworkingComponent

    {
 OkHttpClient httpClient();
 } 
 @Component(dependencies = NetworkingComponent.class)
 interface AppComponent {
 ApiService apiService();
 } class ApiService {
 @Inject ApiService(OkHttpClient httpClient) { … }
 }
  133. Compile as little as possible @Component(modules = NetworkingModule.class)
 interface NetworkingComponent

    {
 OkHttpClient httpClient();
 } 
 @Component(dependencies = NetworkingComponent.class)
 interface AppComponent {
 ApiService apiService();
 } class ApiService {
 @Inject ApiService(OkHttpClient httpClient) { … }
 } separate compilations!
  134. Compile as little as possible public final class DaggerAppComponent implements

    AppComponent { private NetworkingComponent networkComponentDependency; @Override public void ApiService apiService() { return new ApiService(networkComponentDependency.httpClient()); } }
  135. Summarize: Read the generated code

  136. Questions? ronsh@google @rdshapiro