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

Sharper Better Faster Dagger ‡ (Droidcon SF 2016)

Sharper Better Faster Dagger ‡ (Droidcon SF 2016)

For the past 3 years, Square Register Android has leveraged Dagger † to wire up Java objects. However, the app scope hierarchy and complexity increased and we started having bugs and crashes related to scoping errors.

This talk will show how to structure an app around Dagger2 ‡ and present a strategy for incrementally migrating from Dagger1 to Dagger2.

Co-Presented with @Piwai.

Video: https://www.youtube.com/watch?v=7mVRZqsozPw

John Rodriguez

March 17, 2016
Tweet

More Decks by John Rodriguez

Other Decks in Programming

Transcript

  1. SHARPER BETTER FASTER DAGGER ‡ @jrodbx @piwai

  2. SHARPER BETTER FASTER DAGGER ‡

  3. None
  4. // compile 'com.squareup.dagger:dagger:1.2.2'
 // apt 'com.squareup.dagger:dagger-compiler:1.2.2'
 
 compile 'com.google.dagger:dagger:2.0.2'
 apt

    'com.google.dagger:dagger-compiler:2.0.2'
 provided 'javax.annotation:jsr250-api:1.0'
  5. None
  6. @Module(
 injects = { MainActivity.class }, addsTo = AppModule.class
 )


    public final class ApiModule {
 @Provides GithubService provideGithubService(Retrofit retrofit) {
 return retrofit.create(GithubService.class);
 }
 
 @Provides Retrofit provideRetrofit(@Endpoint String url) {
 return new Retrofit.Builder()
 .baseUrl(url)
 .addConverterFactory(GsonConverterFactory.create())
 .build();
 }
 }
  7. @Module(
 injects = { MainActivity.class }, addsTo = AppModule.class
 )


    public final class ApiModule {
 @Provides GithubService provideGithubService(Retrofit retrofit) {
 return retrofit.create(GithubService.class);
 }
 
 @Provides Retrofit provideRetrofit(@Endpoint String url) {
 return new Retrofit.Builder()
 .baseUrl(url)
 .addConverterFactory(GsonConverterFactory.create())
 .build();
 }
 }
  8. @Module(
 injects = { MainActivity.class }, addsTo = AppModule.class
 )


    public final class ApiModule {
 @Provides GithubService provideGithubService(Retrofit retrofit) {
 return retrofit.create(GithubService.class);
 }
 
 @Provides Retrofit provideRetrofit(@Endpoint String url) {
 return new Retrofit.Builder()
 .baseUrl(url)
 .addConverterFactory(GsonConverterFactory.create())
 .build();
 }
 }
  9. public class MainActivity extends Activity {
 @Inject GithubService githubService;
 


    @Override protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 ObjectGraph graph = getObjectGraph();
 objectGraph.inject(this);
  10. public class MainActivity extends Activity {
 @Inject GithubService githubService;
 


    @Override protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 ObjectGraph graph = getObjectGraph();
 objectGraph.inject(this);
  11. @Module(
 injects = { MainActivity.class }, addsTo = AppModule.class
 )


    public final class ApiModule {
 @Provides GithubService provideGithubService(Retrofit retrofit) {
 return retrofit.create(GithubService.class);
 }
 
 @Provides Retrofit provideRetrofit(@Endpoint String url) {
 return new Retrofit.Builder()
 .baseUrl(url)
 .addConverterFactory(GsonConverterFactory.create())
 .build();
 }
 }
  12. @Module
 public final class ApiModule {
 @Provides GithubService provideGithubService(Retrofit retrofit)

    {
 return retrofit.create(GithubService.class);
 }
 
 @Provides Retrofit provideRetrofit(@Endpoint String url) {
 return new Retrofit.Builder()
 .baseUrl(url)
 .addConverterFactory(GsonConverterFactory.create())
 .build();
 }
 }
  13. @Component(
 modules = ApiModule.class
 )
 public interface ApiComponent { Foo

    getFoo();
 void inject(MainActivity activity);
 }
  14. @Component(
 modules = ApiModule.class
 )
 public interface ApiComponent {
 Foo

    getFoo();
 void inject(MainActivity activity); }
  15. public class MainActivity extends Activity {
 @Inject GithubService githubService;
 


    @Override protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 
 ApiComponent apiComponent = DaggerApiComponent.builder().build();
 apiComponent.inject(this); …
  16. public class MainActivity extends Activity {
 @Inject GithubService githubService;
 


    @Override protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 
 ApiComponent apiComponent = DaggerApiComponent.builder().build();
 apiComponent.inject(this); …
  17. @Module class AndroidModule {…} @Module class HttpModule {…}
 @Module class

    ApiModule {…} …
  18. @Module class AndroidModule {…} @Module class HttpModule {…}
 @Module class

    ApiModule {…}
 
 @Module class LoggedInModule {…} @Module class PaymentModule {…} @Module class TransactionLedgerModule {…} …
  19. None
  20. None
  21. @Provides @Inject
 @Module

  22. @Provides @Inject
 @Module @Provides2 @Inject2
 @Module2

  23. ObjectGraph objectGraph = ObjectGraph.create(AppModule.class);

  24. @Module 
 public class AppModule {
 // ...
 @Provides OkHttpClient

    provideOkHttpClient() {
 return new OkHttpClient();
 }
 
 @Provides Client provideRetrofitClient(OkHttpClient client) {
 return new OkClient(client);
 }
 // ...
 }
  25. @Module 
 public class AppModule {
 // ...
 @Provides OkHttpClient

    provideOkHttpClient() {
 return new OkHttpClient();
 }
 
 @Provides Client provideRetrofitClient(OkHttpClient client) {
 return new OkClient(client);
 }
 // ...
 } @Module2 
 public class AppModule2 {
 
 }
  26. @Module 
 public class AppModule {
 // ...
 
 }

    @Module2 
 public class AppModule2 { @Provides2 OkHttpClient provideOkHttpClient() {
 return new OkHttpClient();
 }
 
 @Provides2 Client provideRetrofitClient(OkHttpClient client) {
 return new OkClient(client);
 } }
  27. @Module2 
 public class AppModule2 { @Provides2 OkHttpClient provideOkHttpClient() {


    return new OkHttpClient();
 }
 
 @Provides2 Client provideRetrofitClient(OkHttpClient client) {
 return new OkClient(client);
 } } @Component(modules = AppModule2.class)
 public interface AppComponent {
 
 }
  28. @Module2 
 public class AppModule2 { @Provides2 OkHttpClient provideOkHttpClient() {


    return new OkHttpClient();
 }
 
 @Provides2 Client provideRetrofitClient(OkHttpClient client) {
 return new OkClient(client);
 } } @Component(modules = AppModule2.class)
 public interface AppComponent {
 Client retrofitClient();
 OkHttpClient okHttpClient();
 }
  29. @Component(modules = AppModule2.class)
 public interface AppComponent {
 AppComponentFacade dagger2Facade();
 }

    @Subcomponent
 public interface AppComponentFacade {
 Client retrofitClient();
 OkHttpClient okHttpClient();
 }
  30. @Subcomponent
 public interface AppComponentFacade {
 Client retrofitClient();
 OkHttpClient okHttpClient();
 }

    @Module
 public class BridgeModule {
 private final AppComponentFacade facade;
 
 public BridgeModule(AppComponentFacade facade) {
 this.facade = facade;
 }
 
 @Provides Client retrofitClient() {
 return facade.retrofitClient();
 }
 
 @Provides OkHttpClient okHttpClient() {
 return facade.okHttpClient();
 }
 }
  31. @Subcomponent
 public interface AppComponentFacade {
 Client retrofitClient();
 OkHttpClient okHttpClient();
 }

    @Module
 public class BridgeModule implements AppComponentFacade {
 private final AppComponentFacade facade;
 
 public BridgeModule(AppComponentFacade facade) {
 this.facade = facade;
 }
 
 @Override @Provides public Client retrofitClient() {
 return facade.retrofitClient();
 }
 
 @Override @Provides public OkHttpClient okHttpClient() {
 return facade.okHttpClient();
 }
 }
  32. 
 ObjectGraph objectGraph = ObjectGraph.create(AppModule.class);

  33. AppComponent component = DaggerAppComponent.builder().create();
 ObjectGraph objectGraph = ObjectGraph.create(AppModule.class);

  34. AppComponent component = DaggerAppComponent.builder().create();
 AppComponentFacade facade = component.dagger2Facade();
 ObjectGraph objectGraph

    = ObjectGraph.create(AppModule.class);
  35. AppComponent component = DaggerAppComponent.builder().create();
 AppComponentFacade facade = component.dagger2Facade();
 BridgeModule bridge

    = new BridgeModule(facade);
 ObjectGraph objectGraph = ObjectGraph.create(AppModule.class);
  36. AppComponent component = DaggerAppComponent.builder().create();
 AppComponentFacade facade = component.dagger2Facade();
 BridgeModule bridge

    = new BridgeModule(facade);
 ObjectGraph objectGraph = ObjectGraph.create(bridge, AppModule.class);
  37. @Module2 
 public class AppModule2 { @Provides2 OkHttpClient provideOkHttpClient() {


    return new OkHttpClient();
 }
 
 @Provides2 Client provideRetrofitClient(OkHttpClient client) {
 return new OkClient(client);
 } }
  38. @Module2
 public class AppModule2 {
 @Provides2 OkHttpClient provideOkHttpClient(HostnameVerifier verifier) {


    OkHttpClient okHttpClient = new OkHttpClient();
 okHttpClient.setHostnameVerifier(verifier);
 return okHttpClient;
 }
 
 @Provides2 Client provideRetrofitClient(OkHttpClient client) {
 return new OkClient(client);
 }
 }
  39. @Module
 public class AppModule {
 // ...
 }

  40. @Module(injects = HostnameVerifier.class)
 public class AppModule {
 // ...
 }

  41. @Module(injects = HostnameVerifier.class)
 public class AppModule {
 // ...
 }

    @Module2
 public class GoldenGateModule {
 private ObjectGraph objectGraph;
 
 @Provides2 public HostnameVerifier provideHostnameVerifier() {
 return objectGraph.get(HostnameVerifier.class);
 }
 
 public void setObjectGraph(ObjectGraph objectGraph) {
 this.objectGraph = objectGraph;
 }
 }
  42. @Module2
 public class GoldenGateModule {
 private ObjectGraph objectGraph;
 
 @Provides2

    public HostnameVerifier provideHostnameVerifier() {
 return objectGraph.get(HostnameVerifier.class);
 }
 
 public void setObjectGraph(ObjectGraph objectGraph) {
 this.objectGraph = objectGraph;
 }
 } @Module2 public class AppModule2 {
 
 // ...
 
 }
  43. @Module2
 public class GoldenGateModule {
 private ObjectGraph objectGraph;
 
 @Provides2

    public HostnameVerifier provideHostnameVerifier() {
 return objectGraph.get(HostnameVerifier.class);
 }
 
 public void setObjectGraph(ObjectGraph objectGraph) {
 this.objectGraph = objectGraph;
 }
 } @Module2(includes = GoldenGateModule.class)
 public class AppModule2 {
 
 // ...
 
 }
  44. 
 AppComponent component = DaggerAppComponent.builder().create();
 
 
 AppComponentFacade facade =

    component.dagger2Facade();
 BridgeModule bridge = new BridgeModule(facade);
 ObjectGraph objectGraph = ObjectGraph.create(bridge, AppModule.class);

  45. GoldenGateModule goldenGateModule = new GoldenGateModule();
 AppComponent component = DaggerAppComponent.builder().create();
 


    
 AppComponentFacade facade = component.dagger2Facade();
 BridgeModule bridge = new BridgeModule(facade);
 ObjectGraph objectGraph = ObjectGraph.create(bridge, AppModule.class);

  46. GoldenGateModule goldenGateModule = new GoldenGateModule();
 AppComponent component = DaggerAppComponent.builder()
 .goldenGateModule(goldenGateModule)


    .create();
 AppComponentFacade facade = component.dagger2Facade();
 BridgeModule bridge = new BridgeModule(facade);
 ObjectGraph objectGraph = ObjectGraph.create(bridge, AppModule.class);

  47. GoldenGateModule goldenGateModule = new GoldenGateModule();
 AppComponent component = DaggerAppComponent.builder()
 .goldenGateModule(goldenGateModule)


    .create();
 AppComponentFacade facade = component.dagger2Facade();
 BridgeModule bridge = new BridgeModule(facade);
 ObjectGraph objectGraph = ObjectGraph.create(bridge, AppModule.class);
 goldenGateModule.setObjectGraph(objectGraph);
  48. None
  49. None
  50. Guice Dagger Dagger2 better than Spring…? improved linking + instance

    creation improved linking more (1x per graph)
  51. @Override public ObjectGraph plus(Object... modules) {
 linkEverything();
 return makeGraph(this, plugin,

    modules);
 }
  52. @Override public ObjectGraph plus(Object... modules) {
 linkEverything();
 return makeGraph(this, plugin,

    modules);
 } private Map<String, Binding<?>> linkEverything() {
 … return linker.linkAll();
 } public Map<String, Binding<?>> linkAll() { …
 linkRequested();
 return Collections.unmodifiableMap(bindings);
 }
  53. public void linkRequested() { … while ((binding = toLink.poll()) !=

    null) {
 if (binding instanceof DeferredBinding) { … = createBinding(…, deferred.classLoader, …);
 }
 }
 } private Binding<?> createBinding(…, ClassLoader classLoader, …) {
 … … = instantiate(className.concat(INJECT_ADAPTER_SUFFIX), classLoader); … } protected <T> T instantiate(String name, ClassLoader classLoader) {
 Class<?> generatedClass = loadClass(classLoader, name);
 if (generatedClass == Void.class) return null;
 return (T) generatedClass.newInstance(); }
  54. public void linkRequested() { … while ((binding = toLink.poll()) !=

    null) {
 if (binding instanceof DeferredBinding) { … = createBinding(…, deferred.classLoader, …);
 }
 }
 } private Binding<?> createBinding(…, ClassLoader classLoader, …) {
 … … = instantiate(className.concat(INJECT_ADAPTER_SUFFIX), classLoader); … } protected <T> T instantiate(String name, ClassLoader classLoader) {
 Class<?> generatedClass = loadClass(classLoader, name);
 if (generatedClass == Void.class) return null;
 return (T) generatedClass.newInstance(); }
  55. None
  56. @Module 
 class DripCoffeeModule {
 @Provides static 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.
  57. Scoping!

  58. public class TransactionHandler {
 
 private final Analytics analytics;
 private

    final TaxCache taxCache;
 
 private Payment paymentInFlight;
 private Order order;
 
 @Inject TransactionHandler(Analytics analytics, TaxCache taxCache) {
 this.analytics = analytics;
 this.taxCache = taxCache;
 }
 
 // ...
 }
  59. None
  60. public class TransactionHandler {
 
 private final Analytics analytics;
 private

    final TaxCache taxCache;
 
 private Payment paymentInFlight;
 private Order order;
 
 @Inject TransactionHandler(Analytics analytics, TaxCache taxCache) {
 this.analytics = analytics;
 this.taxCache = taxCache;
 }
 
 // ...
 }
  61. @Singleton public class TransactionHandler {
 
 private final Analytics analytics;


    private final TaxCache taxCache;
 
 private Payment paymentInFlight;
 private Order order;
 
 @Inject TransactionHandler(Analytics analytics, TaxCache taxCache) {
 this.analytics = analytics;
 this.taxCache = taxCache;
 }
 
 // ...
 }
  62. None
  63. public class Linker {
 
 final Map<Class<?>, Binding<?>> bindings =

    new HashMap<>();
 
 <T> Binding<T> requestBinding(Class<T> key) {
 return (Binding<T>) bindings.get(key);
 }
 }
  64. public class Linker {
 
 final Map<Class<?>, Binding<?>> bindings =

    new HashMap<>();
 
 <T> Binding<T> requestBinding(Class<T> key) {
 return (Binding<T>) bindings.get(key);
 }
 }
  65. public abstract class Binding<T> {
 
 final boolean singleton;
 


    protected Binding(boolean singleton) {
 this.singleton = singleton;
 }
 
 abstract void attach(Linker linker);
 
 abstract T get();
 }
  66. public abstract class Binding<T> {
 
 final boolean singleton;
 


    protected Binding(boolean singleton) {
 this.singleton = singleton;
 }
 
 abstract void attach(Linker linker);
 
 abstract T get();
 }
  67. public abstract class Binding<T> {
 
 final boolean singleton;
 


    protected Binding(boolean singleton) {
 this.singleton = singleton;
 }
 
 abstract void attach(Linker linker);
 
 abstract T get();
 }
  68. public abstract class Binding<T> {
 
 final boolean singleton;
 


    protected Binding(boolean singleton) {
 this.singleton = singleton;
 }
 
 abstract void attach(Linker linker);
 
 abstract T get();
 }
  69. public class TransactionHandler$$InjectAdapter extends Binding<TransactionHandler> {
 
 private Binding<TaxCache> taxCache;


    private Binding<Analytics> analytics;
 
 public TransactionHandler$$InjectAdapter() {
 super(IS_SINGLETON);
 }
 
 @Override public void attach(Linker linker) {
 analytics = linker.requestBinding(Analytics.class);
 taxCache = linker.requestBinding(TaxCache.class);
 }
 
 @Override public TransactionHandler get() {
 return new TransactionHandler(analytics.get(), taxCache.get());
 }
 }
  70. public class TransactionHandler$$InjectAdapter extends Binding<TransactionHandler> {
 
 private Binding<TaxCache> taxCache;


    private Binding<Analytics> analytics;
 
 public TransactionHandler$$InjectAdapter() {
 super(IS_SINGLETON);
 }
 
 @Override public void attach(Linker linker) {
 analytics = linker.requestBinding(Analytics.class);
 taxCache = linker.requestBinding(TaxCache.class);
 }
 
 @Override public TransactionHandler get() {
 return new TransactionHandler(analytics.get(), taxCache.get());
 }
 }
  71. public class TransactionHandler$$InjectAdapter extends Binding<TransactionHandler> {
 
 private Binding<TaxCache> taxCache;


    private Binding<Analytics> analytics;
 
 public TransactionHandler$$InjectAdapter() {
 super(IS_SINGLETON);
 }
 
 @Override public void attach(Linker linker) {
 analytics = linker.requestBinding(Analytics.class);
 taxCache = linker.requestBinding(TaxCache.class);
 }
 
 @Override public TransactionHandler get() {
 return new TransactionHandler(analytics.get(), taxCache.get());
 }
 }
  72. public class SingletonBinding<T> extends Binding<T> {
 final Binding<T> delegate;
 


    T instance;
 
 SingletonBinding(Binding<T> delegate) {
 this.delegate = delegate;
 }
 
 @Override void attach(Linker linker) {
 delegate.attach(linker);
 }
 
 @Override T get() {
 if (instance == null) {
 instance = delegate.get();
 }
 return instance;
 }
 }
  73. public class SingletonBinding<T> extends Binding<T> {
 final Binding<T> delegate;
 


    T instance;
 
 SingletonBinding(Binding<T> delegate) {
 this.delegate = delegate;
 }
 
 @Override void attach(Linker linker) {
 delegate.attach(linker);
 }
 
 @Override T get() {
 if (instance == null) {
 instance = delegate.get();
 }
 return instance;
 }
 }
  74. ObjectGraph Linker SingletonBinding Binding TransactionHandler Binding Binding

  75. None
  76. None
  77. ObjectGraph TransactionHandler

  78. ObjectGraph TransactionHandler

  79. ObjectGraph TransactionHandler PrinterHandler

  80. ObjectGraph TransactionHandler PrinterHandler ObjectGraph

  81. ObjectGraph TransactionHandler PrinterHandler ObjectGraph ObjectGraph AppSingleton

  82. Transaction PrintScreen App

  83. None
  84. @Singleton public class TransactionHandler {
 
 private final Analytics analytics;


    private final TaxCache taxCache;
 
 private Payment paymentInFlight;
 private Order order;
 
 @Inject TransactionHandler(Analytics analytics, TaxCache taxCache) {
 this.analytics = analytics;
 this.taxCache = taxCache;
 }
 
 // ...
 }
  85. public class TransactionFlow {
 
 private final TransactionHandler transactionHandler;
 


    @Inject TransactionFlow(TransactionHandler transactionHandler) {
 this.transactionHandler = transactionHandler;
 }
 // ...
 }
  86. public class TransactionFlow {
 
 private final TransactionHandler transactionHandler;
 


    @Inject TransactionFlow(TransactionHandler transactionHandler) {
 this.transactionHandler = transactionHandler;
 }
 // ...
 } public class TransactionFlowLayout extends FrameLayout {
 
 public TransactionFlowLayout(Context context, AttributeSet attrs) {
 super(context, attrs);
 TransactionFlow transactionFlow = ???;
 // ...
 }
 }
  87. @Module(injects = TransactionFlow.class)
 class TransactionModule {
 }

  88. ObjectGraph transactionGraph = appGraph.plus(TransactionModule.class); @Module(injects = TransactionFlow.class)
 class TransactionModule {


    }
  89. ObjectGraph transactionGraph = appGraph.plus(TransactionModule.class); @Module(injects = TransactionFlow.class)
 class TransactionModule {


    } public class TransactionFlowLayout extends FrameLayout {
 
 public TransactionFlowLayout(Context context, AttributeSet attrs) {
 super(context, attrs); ObjectGraph graph = getTransactionGraph();
 TransactionFlow transactionFlow = graph.get(TransactionFlow.class);
 // ...
 }
 }
  90. public class CartPresenter {
 
 private final TransactionHandler transactionHandler;
 


    @Inject CartPresenter(TransactionHandler transactionHandler) {
 this.transactionHandler = transactionHandler;
 }
 // ...
 }
  91. public class CartPresenter {
 
 private final TransactionHandler transactionHandler;
 


    @Inject CartPresenter(TransactionHandler transactionHandler) {
 this.transactionHandler = transactionHandler;
 }
 // ...
 } public class CartView extends CoordinatorLayout {
 
 public CartView(Context context, AttributeSet attrs) {
 super(context, attrs);
 ObjectGraph cartGraph = getCartGraph();
 CartPresenter cartPresenter = cartGraph.get(CartPresenter.class);
 // ...
 }
 }
  92. public class CartPresenter {
 
 private final TransactionHandler transactionHandler;
 


    @Inject CartPresenter(TransactionHandler transactionHandler) {
 this.transactionHandler = transactionHandler;
 }
 // ...
 } public class CartView extends CoordinatorLayout {
 
 public CartView(Context context, AttributeSet attrs) {
 super(context, attrs);
 ObjectGraph cartGraph = getCartGraph();
 CartPresenter cartPresenter = cartGraph.get(CartPresenter.class);
 // ...
 }
 }
  93. ObjectGraph transactionGraph = appGraph.plus(TransactionModule.class); 
 ObjectGraph cartGraph = transactionGraph.plus(CartScreenModule.class);

  94. ObjectGraph transactionGraph = appGraph.plus(TransactionModule.class); 
 ObjectGraph cartGraph = transactionGraph.plus(CartScreenModule.class); @Module(injects

    = TransactionFlow.class)
 class TransactionModule {
 } @Module(injects = CartPresenter.class)
 class CartScreenModule {
 }
  95. public class ObjectGraph {
 
 Linker linker;
 
 public <T>

    T get(Class<T> key) {
 Binding<T> binding = linker.requestBinding(key);
 return binding.get();
 }
 }
  96. public class ObjectGraph {
 
 Linker linker;
 ObjectGraph parentGraph;
 


    public <T> T get(Class<T> key) {
 if (parentGraph != null) {
 T instance = parentGraph.get(key);
 if (instance != null) {
 return instance;
 }
 }
 Binding<T> binding = linker.requestBinding(key);
 return binding.get();
 }
 }
  97. public class Linker {
 
 final Map<Class<?>, Binding<?>> bindings =

    new HashMap<>();
 
 <T> Binding<T> requestBinding(Class<T> key) {
 return (Binding<T>) bindings.get(key);
 }
 }
  98. public class Linker {
 
 final Map<Class<?>, Binding<?>> bindings =

    new HashMap<>();
 
 <T> Binding<T> requestBinding(Class<T> key) {
 Binding<T> binding = (Binding<T>) bindings.get(key);
 if (binding == null) {
 binding = loadGeneratedBinding(key);
 if (binding.singleton) {
 binding = new SingletonBinding<>(binding);
 }
 bindings.put(key, binding);
 }
 return binding;
 }
 }
  99. Binding Binding CartPresenter TransactionFlow Cart screen graph Transaction graph SingletonBinding

    TransactionHandler
  100. None
  101. Binding Binding CartPresenter TransactionFlow Cart screen graph Transaction graph SingletonBinding

    TransactionHandler
  102. None
  103. None
  104. com.squareup.Transaction binding found in scopes marked with '*' (if any).

    SCOPE RegisterRootScope +-SCOPE com.squareup.dagger.LoggedIn | `-SCOPE com.squareup.ui.root.RootActivity | `-SCOPE * com.squareup.ui.root.RootFlow | `-SCOPE com.squareup.ui.seller.SellerFlow | `-SCOPE com.squareup.ui.home.HomeScreen `-SCOPE com.squareup.ui.PaymentActivity
  105. @Module(injects = TransactionFlow.class)
 class TransactionModule {
 } ObjectGraph transactionGraph =

    appGraph.plus(TransactionModule.class);
  106. @Module(injects = TransactionFlow.class)
 class TransactionModule {
 
 @Provides @Singleton TransactionHandler

    transactionHandler(Analytics analytics,
 TaxCache taxCache) {
 return new TransactionHandler(analytics, taxCache);
 }
 } ObjectGraph transactionGraph = appGraph.plus(TransactionModule.class);
  107. @Singleton public class TransactionHandler {...} @Module(injects = TransactionFlow.class)
 public class

    TransactionModule {}
  108. @Singleton public class TransactionHandler {...} @Module(injects = TransactionFlow.class)
 public class

    TransactionModule {} @Scope public @interface SingleInTransaction {}
  109. @SingleInTransaction public class TransactionHandler {...} @Module(injects = TransactionFlow.class)
 public class

    TransactionModule {} @Scope public @interface SingleInTransaction {}
  110. @SingleInTransaction public class TransactionHandler {...} @Module(injects = TransactionFlow.class)
 public class

    TransactionModule {} @Scope public @interface SingleInTransaction {} 
 @Component 
 interface TransactionComponent {
 }
  111. @SingleInTransaction public class TransactionHandler {...} @Module(injects = TransactionFlow.class)
 public class

    TransactionModule {} @Scope public @interface SingleInTransaction {} @SingleInTransaction
 @Component 
 interface TransactionComponent {
 }
  112. @SingleInTransaction public class TransactionHandler {...} @Module(injects = TransactionFlow.class)
 public class

    TransactionModule {} @Scope public @interface SingleInTransaction {} @SingleInTransaction
 @Component(modules = TransactionModule.class) 
 interface TransactionComponent {
 }
  113. @SingleInTransaction public class TransactionHandler {...} @Module
 public class TransactionModule {}

    @Scope public @interface SingleInTransaction {} @SingleInTransaction
 @Component(modules = TransactionModule.class) 
 interface TransactionComponent {
 TransactionFlow transactionFlow();
 }
  114. @SingleInTransaction public class TransactionHandler {...} @Module
 public class TransactionModule {}

    @Scope public @interface SingleInTransaction {} @SingleInTransaction
 @Component(modules = TransactionModule.class) 
 interface TransactionComponent {
 TransactionFlow transactionFlow();
 }
  115. @SingleInTransaction public class TransactionHandler {...} @Module
 public class TransactionModule {}

    @Scope public @interface SingleIn { Class<?> value(); } @SingleInTransaction
 @Component(modules = TransactionModule.class) 
 interface TransactionComponent {
 TransactionFlow transactionFlow();
 }
  116. @SingleIn(TransactionComponent.class) public class TransactionHandler {...} @Module
 public class TransactionModule {}

    @Scope public @interface SingleIn { Class<?> value(); } @SingleInTransaction
 @Component(modules = TransactionModule.class) 
 interface TransactionComponent {
 TransactionFlow transactionFlow();
 }
  117. @SingleIn(TransactionComponent.class) public class TransactionHandler {...} @Module
 public class TransactionModule {}

    @Scope public @interface SingleIn { Class<?> value(); } @SingleIn(TransactionComponent.class)
 @Component(modules = TransactionModule.class) 
 interface TransactionComponent {
 TransactionFlow transactionFlow();
 }
  118. None
  119. Transaction flow graph Print screen graph App graph Cart screen

    graph
  120. Transaction flow graph Print screen graph App graph Cart screen

    graph
  121. Transaction flow graph Print screen graph App graph Cart screen

    graph proxy graph
  122. None
  123. Transaction flow graph Print screen graph App graph Cart screen

    graph
  124. Transaction flow graph Print screen graph App graph Cart screen

    graph
  125. @Component
 public interface CartScreenComponent {
 CartPresenter cartPresenter();
 }

  126. @Component(modules = CartScreenModule.class)
 public interface CartScreenComponent {
 CartPresenter cartPresenter();
 }

  127. public interface CartScreenDependencies {
 TransactionHandler transactionHandler();
 } @Component(modules = CartScreenModule.class,

    dependencies = CartScreenDependencies.class)
 public interface CartScreenComponent {
 CartPresenter cartPresenter();
 }
  128. None
  129. @jrodbx @piwai