Dagger 2 Android : Defeat the Dahaka DevFestND 2017

A3958eeb9a7f402b134c0c017d6614ee?s=47 ragdroid
October 28, 2017

Dagger 2 Android : Defeat the Dahaka DevFestND 2017

Ppt for DevFest New Delhi, 2017 (Noida Track) @ToTheNew

Github Demo : https://github.com/ragdroid/Dahaka
Medium Blogs : https://proandroiddev.com/dagger-2-android-defeat-the-dahaka-b1c542233efc

A3958eeb9a7f402b134c0c017d6614ee?s=128

ragdroid

October 28, 2017
Tweet

Transcript

  1. “Defeat the Dahaka" Dagger 2 Android Garima Jain @ragdroid

  2. Garima Jain @ragdroid

  3. Garima Jain @ragdroid

  4. Garima Jain @ragdroid

  5. Garima Jain @ragdroid

  6. Garima Jain @ragdroid

  7. Garima Jain @ragdroid

  8. @ragdroid @droidconDE

  9. @ragdroid @droidconDE MVP Testing DataBinding Retrofit Dagger 2

  10. Garima Jain @ragdroid “Defeat the Dahaka" Dagger 2 Android

  11. @ragdroid @droidconDE POP QUIZ • Dagger2? • Dagger Android •

    Prince of Persia
  12. ABOUT THE TALK

  13. Theme: Prince of Persia • Prince uses Dagger • Dagger

    can reverse time • Dahaka, (guardian of timeline) • Dahaka comes to kill the Prince.
  14. Analogy • Prince = Us • Dagger = Dagger •

    Dahaka (Enemy) = Generated Code, Complexity
  15. Analogy • Developer uses Dagger • Developer starts backtracking the

    generated code • Developer is chased by the Dahaka (complexity of generated code)
  16. Agenda • Brief Introduction - “Codes of Time” • Scopes

    - “Face of the Dahaka” • @Singleton Scopes • @Reusable Scopes • Custom Scopes • Component Dependencies - “Unleash the Beast” • Demo App • Dependent Component • Subcomponent • Intermediate Concepts - “Defeat the Dahaka” • Dagger Android - “Befriend the Beast”
  17. Who? • Assumption : Basic familiarity with Dagger • Intermediate

  18. INTRODUCTION “CODES OF TIME”

  19. @ragdroid @droidconDE Droid of Asia

  20. @ragdroid @droidconDE public UserManager() {
 this.service = new PokemonService(); 


    } Droid of Asia
  21. @ragdroid @droidconDE Dependency Creation Disadvantages • Non-Testable • Non-Extendable

  22. @ragdroid @droidconDE Dagger 1

  23. @ragdroid @droidconDE Dagger 1 Advantages • Testable code • Modularized

  24. @ragdroid @droidconDE Dagger 1 Disadvantages • Reflection • Runtime Graph

    Composition • God Module with @Singleton • Difficult to use proguard
  25. @ragdroid @droidconDE Dagger 1 Disadvantages Dagger 2

  26. @ragdroid @droidconDE Dagger 2 Advantages • No Reflection • Compile-time

    Graph Composition • Traceable code • Better Scope management
  27. SCOPES “FACE OF THE DAHAKA”

  28. Scope • Annotation from java.inject package • How long a

    scoped instance lives
  29. @Singleton • Scope of dependency is throughout the application •

    Two ways to re-use dependencies : • Annotate Provider methods • Annotate the Dependency class itself (javax.inject)
  30. @ragdroid @droidconDE @SINGLETON VS NO SCOPE EXAMPLE

  31. AppComponent @Component(modules = AppModule.class) @Singleton public interface AppComponent { SomeDependency

    someDependency(); }
  32. AppComponent @Component(modules = AppModule.class) @Singleton public interface AppComponent { SomeDependency

    someDependency(); } AppComponent
  33. @ragdroid @droidconDE CASE 1 DEPENDENCY W/O SCOPE

  34. AppModule @Module public class AppModule { @Provides //No @Singleton annotation

    SomeDependency applicationProvider() { return new SomeDependency(); } }
  35. AppModule @Module public class AppModule { @Provides //No @Singleton annotation

    SomeDependency applicationProvider() { return new SomeDependency(); } }
  36. DaggerAppComponent @Generated public final class DaggerAppComponent implements AppComponent { private

    Provider<SomeDependency> someDependencyProvider; /** other code **/ private void initialize(final Builder builder) { this.someDependencyProvider = AppModule_SomeDependencyFactory.create(builder.appModule); } } (Generated)
  37. DaggerAppComponent @Generated public final class DaggerAppComponent implements AppComponent { private

    Provider<SomeDependency> someDependencyProvider; /** other code **/ private void initialize(final Builder builder) { this.someDependencyProvider = AppModule_SomeDependencyFactory.create(builder.appModule); } } (Generated)
  38. DaggerAppComponent @Generated public final class DaggerAppComponent implements AppComponent { private

    Provider<SomeDependency> someDependencyProvider; /** other code **/ private void initialize(final Builder builder) { this.someDependencyProvider = AppModule_SomeDependencyFactory.create(builder.appModule); } } (Generated)
  39. @ragdroid @droidconDE CASE 2 DEPENDENCY WITH SCOPE

  40. AppModule @Module public class AppModule { @Provides @Singleton SomeDependency applicationProvider()

    { return new SomeDependency; } }
  41. AppModule @Module public class AppModule { @Provides @Singleton SomeDependency applicationProvider()

    { return new SomeDependency; } }
  42. DaggerAppComponent @Generated public final class DaggerAppComponent implements AppComponent { private

    Provider<SomeDependency> someDependencyProvider; /** other code **/ private void initialize(final Builder builder) { this.someDependencyProvider = DoubleCheck.provider( AppModule_SomeDependencyFactory.create(builder.appModule)); } } (Generated)
  43. DaggerAppComponent (Generated) @Generated public final class DaggerAppComponent implements AppComponent {

    private Provider<SomeDependency> someDependencyProvider; /** other code **/ private void initialize(final Builder builder) { this.someDependencyProvider = DoubleCheck.provider( AppModule_SomeDependencyFactory.create(builder.appModule)); } }
  44. DaggerAppComponent (Generated) @Generated public final class DaggerAppComponent implements AppComponent {

    private Provider<SomeDependency> someDependencyProvider; /** other code **/ private void initialize(final Builder builder) { this.someDependencyProvider = DoubleCheck.provider( AppModule_SomeDependencyFactory.create(builder.appModule)); } }
  45. DoubleCheck Memoizes value using Double-Check idiom. (dagger.internal)

  46. DoubleCheck Memoizes value using Double-Check idiom. public T get() {


    Object result = instance;
 if (result == UNINITIALIZED) {
 synchronized (this) {
 result = instance;
 if (result == UNINITIALIZED) {
 result = provider.get();
 
 Object currentInstance = instance; // other code
 instance = result;
 
 provider = null;
 }
 }
 }
 return (T) result;
 } (dagger.internal)
  47. DoubleCheck Memoizes value using Double-Check idiom. public T get() {


    Object result = instance;
 if (result == UNINITIALIZED) {
 synchronized (this) {
 result = instance;
 if (result == UNINITIALIZED) {
 result = provider.get();
 
 Object currentInstance = instance; // other code
 instance = result;
 
 provider = null;
 }
 }
 }
 return (T) result;
 } (dagger.internal)
  48. DoubleCheck Memoizes value using Double-Check idiom. public T get() {


    Object result = instance;
 if (result == UNINITIALIZED) {
 synchronized (this) {
 result = instance;
 if (result == UNINITIALIZED) {
 result = provider.get();
 
 Object currentInstance = instance; // other code
 instance = result;
 
 provider = null;
 }
 }
 }
 return (T) result;
 } (dagger.internal)
  49. Take Aways • DONT “Scope All the Things!” • Scoping

    has overheads. • By-default no Scope. • Scope only when needed • Like for Heavy Mutable Objects
  50. @ragdroid @droidconDE @REUSABLE

  51. @Reusable • Limit the instantiation. • Use when Exact same

    instance not needed. • Not tied to any component or subcomponent. • Can Have multiple sub-components caching different instances. • Use for heavy immutable dependencies.
  52. ReusableComponent 
 @Component(modules = ReusableModule.class) public interface ReusableComponent { SomeObject

    someObject(); }
  53. ReusableComponent 
 @Component(modules = ReusableModule.class) public interface ReusableComponent { SomeObject

    someObject(); }
  54. SomeObject @Reusable public class SomeObject { @Inject public SomeObject() {

    } }
  55. DaggerReusableComponent @Generated public final class DaggerReusableComponent implements ReusableComponent { /**

    other code **/ Provider<SomeObject> someObjectProvider; private void initialize(final Builder builder) { this.someObjectProvider = SingleCheck.provider(SomeObject_Factory.create()); } } (Generated)
  56. DaggerReusableComponent @Generated public final class DaggerReusableComponent implements ReusableComponent { /**

    other code **/ Provider<SomeObject> someObjectProvider; private void initialize(final Builder builder) { this.someObjectProvider = SingleCheck.provider(SomeObject_Factory.create()); } } (Generated)
  57. DaggerReusableComponent @Generated public final class DaggerReusableComponent implements ReusableComponent { /**

    other code **/ Provider<SomeObject> someObjectProvider; private void initialize(final Builder builder) { this.someObjectProvider = SingleCheck.provider(SomeObject_Factory.create()); } } (Generated)
  58. SingleCheck Memoizes value using simple lazy initialization and caching (dagger.internal)

  59. Memoizes value using simple lazy initialization and caching public T

    get() {
 
 Provider<T> providerReference = provider;
 if (instance == UNINITIALIZED) {
 instance = providerReference.get();
 provider = null;
 }
 return (T) instance;
 } (dagger.internal) SingleCheck
  60. Memoizes value using simple lazy initialization and caching public T

    get() {
 
 Provider<T> providerReference = provider;
 if (instance == UNINITIALIZED) {
 instance = providerReference.get();
 provider = null;
 }
 return (T) instance;
 } (dagger.internal) SingleCheck
  61. No Scope vs @Singleton vs @Reusable • Not Heavy :

    No Scope • Heavy mutable object : @Singleton • Heavy immutable object : @Reusable •
  62. @ragdroid @droidconDE GOD APP MODULE

  63. @ragdroid @droidconDE App Module AppComponent @Module public class AppModule {

    private final Application application; @Provides @Si AppModule @Singleton @Component(modules = AppModule.class) @Singleton public interface AppComponent { Application application(); }
  64. @ragdroid @droidconDE Big App Module AppComponent @Module public class AppModule

    { private final Application application; @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton AppModule @Singleton @Component(modules = AppModule.class) @Singleton public interface AppComponent { Application application(); }
  65. @ragdroid @droidconDE AppComponent @Module public class AppModule { private final

    Application application; @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } } AppModule @Singleton Big App Module @Component(modules = AppModule.class) @Singleton public interface AppComponent { Application application(); }
  66. @ragdroid @droidconDE AppComponent @Module public class AppModule { private final

    Application application; @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } } AppModule @Singleton God Module God App Module @Component(modules = AppModule.class) @Singleton public interface AppComponent { Application application(); }
  67. @ragdroid @droidconDE God App Module How To Improve?

  68. @ragdroid @droidconDE God App Module Splitting App Module

  69. @ragdroid @droidconDE AppComponent @Module public class AppModule { private final

    Application application; @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } } @Singleton @Component(modules = AppModule.class) @Singleton public interface AppComponent { Application application(); } Splitting App Module ApiModule AppModule
  70. @ragdroid @droidconDE Splitting App Module @Module public class AppModule {

    private final Application application; @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } } AppModule ApiModule AppComponent @Singleton @Component(modules = AppModule.class) @Singleton public interface AppComponent { Application application(); }
  71. @ragdroid @droidconDE Splitting App Module AppComponent @Module public class AppModule

    { private final Application application; @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } } AppModule @Singleton @Component(modules = AppModule.class) @Singleton public interface AppComponent { Application application(); } ApiModule @Component( modules = AppModule.class, ApiModule.class)
  72. @ragdroid @droidconDE Splitting App Module @Module public class AppModule {

    private final Application application; @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } } AppModule ApiModule @Component( modules = AppModule.class, ApiModule.class) OR AppComponent
  73. @ragdroid @droidconDE Splitting App Module @Module public class AppModule {

    private final Application application; @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } @Provides @Singleton Application applicationProvider() { return application; } } AppModule ApiModule @Component( modules = AppModule.class, ApiModule.class) @Module( includes = ApiModule.class) AppModule OR AppComponent
  74. @ragdroid @droidconDE Splitting App Module

  75. @ragdroid @droidconDE How to Improve? • Better Scope Management •

    More modularity • Custom Scopes : • @UserScope • @ActivityScope • @FragmentScope
  76. @ragdroid @droidconDE Custom Scopes

  77. @ragdroid @droidconDE Custom Scopes Multiple Components

  78. Multiple Components 1. Dependent Components 2. Sub-Components

  79. COMPONENT DEPENDENCIES

  80. @ragdroid @droidconDE POKEMON APP

  81. AppComponent (@Singleton) UserComponent (@UserScope) UserComponent @UserScope Login Component @ActivityScope Home

    Component Items Component Login Component Home Component Items Component Fragments Fragments Application
  82. AppComponent (@Singleton) UserComponent (@UserScope) UserComponent @UserScope Login Component @ActivityScope Home

    Component Items Component Login Component Home Component Items Component Fragments Fragments Launch Application
  83. AppComponent (@Singleton) UserComponent (@UserScope) UserComponent @UserScope Login Component @ActivityScope Home

    Component Items Component Login Component Home Component Items Component Fragments Fragments Launch pikachu Login Application
  84. AppComponent (@Singleton) UserComponent (@UserScope) UserComponent @UserScope Login Component @ActivityScope Home

    Component Items Component Login Component Home Component Items Component Fragments Fragments Launch pikachu Login Inventory Application
  85. AppComponent (@Singleton) UserComponent (@UserScope) UserComponent @UserScope Login Component @ActivityScope Home

    Component Items Component Login Component Home Component Items Component Fragments Fragments Launch pikachu Login Log-Out Inventory Application
  86. AppComponent (@Singleton) UserComponent (@UserScope) UserComponent @UserScope Login Component @ActivityScope Home

    Component Items Component Login Component Home Component Items Component Fragments Fragments Launch pikachu Login Log-Out jigglypuff Inventory Application
  87. AppComponent (@Singleton) UserComponent (@UserScope) UserComponent @UserScope Login Component @ActivityScope Home

    Component Items Component Login Component Home Component Items Component Fragments Fragments Launch pikachu Login Log-Out jigglypuff Inventory Inventory Application
  88. Pokemon App

  89. @ragdroid @droidconDE SUB COMPONENT VS DEPENDENT COMPONENT

  90. <<interface>> AppComponent schedulerProvider @Singleton

  91. AppComponentImpl • schedulerProvider() : @Singleton • userManager : @Singleton LoginComponentImpl

    <<interface>> AppComponent schedulerProvider Login Sub Component @Singleton @ActivityScope
  92. UserComponentImpl • schedulerProvider • pokemon AppComponentImpl • schedulerProvider() : @Singleton

    • userManager : @Singleton LoginComponentImpl <<interface>> AppComponent schedulerProvider HomeComponentImpl ItemsComponentImpl @Singleton @ActivityScope @UserScope @ActivityScope @ActivityScope Login Sub Component User Dependent Component
  93. UserComponentImpl • schedulerProvider • pokemon AppComponentImpl • schedulerProvider() : @Singleton

    • userManager : @Singleton LoginComponentImpl <<interface>> AppComponent schedulerProvider HomeComponentImpl ItemsComponentImpl User Dependent Component @Singleton @ActivityScope @UserScope @ActivityScope @ActivityScope Login Sub Component
  94. @ragdroid @droidconDE APP COMPONENT

  95. @Singleton @Component(modules = arrayOf(AppModule::class, ApiModule::class)) interface AppComponent { fun loginBuilder():

    LoginComponent.Builder fun schedulerProvider(): BaseSchedulerProvider } AppComponent
  96. @Singleton @Component(modules = arrayOf(AppModule::class, ApiModule::class)) interface AppComponent { fun loginBuilder():

    LoginComponent.Builder fun schedulerProvider(): BaseSchedulerProvider } AppComponent
  97. @Singleton @Component(modules = arrayOf(AppModule::class, ApiModule::class)) interface AppComponent { fun loginBuilder():

    LoginComponent.Builder fun schedulerProvider(): BaseSchedulerProvider } AppComponent
  98. @ragdroid @droidconDE DAHAKA APPLICATION

  99. class DahakaApplication : Application() { override fun onCreate() { super.onCreate()

    appComponent = DaggerAppComponent .builder() .application(this) .build() } } DahakaApplication
  100. class DahakaApplication : Application() { override fun onCreate() { super.onCreate()

    appComponent = DaggerAppComponent .builder() .application(this) .build() } } DahakaApplication
  101. DEPENDENT COMPONENTS

  102. @ragdroid @droidconDE USER COMPONENT

  103. @Component(dependencies = arrayOf(AppComponent::class), modules = arrayOf(UserModule::class)) @UserScope interface UserComponent {

    @Component.Builder interface Builder { @BindsInstance fun pokeMon(pokemon: Pokemon): Builder … } } UserComponent
  104. @Component(dependencies = arrayOf(AppComponent::class), modules = arrayOf(UserModule::class)) @UserScope interface UserComponent {

    @Component.Builder interface Builder { @BindsInstance fun pokeMon(pokemon: Pokemon): Builder … } } UserComponent
  105. @Component(dependencies = arrayOf(AppComponent::class), modules = arrayOf(UserModule::class)) @UserScope interface UserComponent {

    @Component.Builder interface Builder { @BindsInstance fun pokeMon(pokemon: Pokemon): Builder … } } UserComponent
  106. Binding Pokemon • Two ways of Providing / Binding Pokemon

    to graph 1. UserModule Constructor 2. @Component.Builder with @BindsInstance
  107. 
 @Module
 public abstract class UserModule {
 
 private final

    Pokemon pokemon;
 
 public UserModule(Pokemon pokemon) {
 this.pokemon = pokemon;
 }
 
 @Provides
 @UserScope
 public Pokemon providePokemon() {
 return pokemon;
 }
 
 }
 UserModule Constructor
  108. 
 @Module
 public abstract class UserModule {
 
 private final

    Pokemon pokemon;
 
 public UserModule(Pokemon pokemon) {
 this.pokemon = pokemon;
 }
 
 @Provides
 @UserScope
 public Pokemon providePokemon() {
 return pokemon;
 }
 
 }
 UserModule Constructor
  109. 
 @Module
 public abstract class UserModule {
 
 private final

    Pokemon pokemon;
 
 public UserModule(Pokemon pokemon) {
 this.pokemon = pokemon;
 }
 
 @Provides
 @UserScope
 public Pokemon providePokemon() {
 return pokemon;
 }
 
 }
 UserModule Constructor
  110. @Component(dependencies = arrayOf(AppComponent::class), modules = arrayOf(UserModule::class)) @UserScope interface UserComponent {

    @Component.Builder interface Builder { @BindsInstance fun pokeMon(pokemon: Pokemon): Builder … } } User Component @Component.Builder
  111. @Component(dependencies = arrayOf(AppComponent::class), modules = arrayOf(UserModule::class)) @UserScope interface UserComponent {

    @Component.Builder interface Builder { @BindsInstance fun pokeMon(pokemon: Pokemon): Builder … } } UserComponent @BindsInstance
  112. @ragdroid @droidconDE USER MANAGER

  113. @Singleton class UserManager @Inject constructor(private val service: PokemonService) { var

    userComponent: UserComponent? = null private set public fun createUserSession(pokemon: Pokemon) { userComponent = DaggerUserComponent.builder() .appComponent(DahakaApplication.app.appComponent) .pokeMon(pokemon) .build() } … } UserManager
  114. @Singleton class UserManager @Inject constructor(private val service: PokemonService) { var

    userComponent: UserComponent? = null private set public fun createUserSession(pokemon: Pokemon) { userComponent = DaggerUserComponent.builder() .appComponent(DahakaApplication.app.appComponent) .pokeMon(pokemon) .build() } … } UserManager
  115. @Singleton class UserManager @Inject constructor(private val service: PokemonService) { var

    userComponent: UserComponent? = null private set public fun createUserSession(pokemon: Pokemon) { userComponent = DaggerUserComponent.builder() .appComponent(DahakaApplication.app.appComponent) .pokeMon(pokemon) .build() } … } UserManager
  116. @ragdroid @droidconDE DAGGER USER COMPONENT (Generated)

  117. public final class DaggerUserComponent implements UserComponent { private Provider<BaseSchedulerProvider> schedulerProvider;

    private void initialize(final Builder builder) { this.schedulerProvider = new AppComponent_schedulerProvider(builder.appComponent); … } private static class AppComponent_schedulerProvider implements Provider<BaseSchedulerProvider> { private final AppComponent appComponent; @Override public BaseSchedulerProvider get() { return appComponent.schedulerProvider(); } … } } DaggerUserComponent (Generated)
  118. public final class DaggerUserComponent implements UserComponent { private Provider<BaseSchedulerProvider> schedulerProvider;

    private void initialize(final Builder builder) { this.schedulerProvider = new AppComponent_schedulerProvider(builder.appComponent); … } private static class AppComponent_schedulerProvider implements Provider<BaseSchedulerProvider> { private final AppComponent appComponent; @Override public BaseSchedulerProvider get() { return appComponent.schedulerProvider(); } … } } DaggerUserComponent (Generated)
  119. public final class DaggerUserComponent implements UserComponent { private Provider<BaseSchedulerProvider> schedulerProvider;

    private void initialize(final Builder builder) { this.schedulerProvider = new AppComponent_schedulerProvider(builder.appComponent); … } private static class AppComponent_schedulerProvider implements Provider<BaseSchedulerProvider> { private final AppComponent appComponent; @Override public BaseSchedulerProvider get() { return appComponent.schedulerProvider(); } … } } DaggerUserComponent (Generated)
  120. public final class DaggerUserComponent implements UserComponent { private Provider<BaseSchedulerProvider> schedulerProvider;

    private void initialize(final Builder builder) { this.schedulerProvider = new AppComponent_schedulerProvider(builder.appComponent); … } private static class AppComponent_schedulerProvider implements Provider<BaseSchedulerProvider> { private final AppComponent appComponent; @Override public BaseSchedulerProvider get() { return appComponent.schedulerProvider(); } … } } DaggerUserComponent (Generated)
  121. public final class DaggerUserComponent implements UserComponent { private Provider<BaseSchedulerProvider> schedulerProvider;

    private void initialize(final Builder builder) { this.schedulerProvider = new AppComponent_schedulerProvider(builder.appComponent); … } private static class AppComponent_schedulerProvider implements Provider<BaseSchedulerProvider> { private final AppComponent appComponent; @Override public BaseSchedulerProvider get() { return appComponent.schedulerProvider(); } … } } DaggerUserComponent (Generated)
  122. public final class DaggerUserComponent implements UserComponent { private Provider<BaseSchedulerProvider> schedulerProvider;

    private void initialize(final Builder builder) { this.schedulerProvider = new AppComponent_schedulerProvider(builder.appComponent); … } private static class AppComponent_schedulerProvider implements Provider<BaseSchedulerProvider> { private final AppComponent appComponent; @Override public BaseSchedulerProvider get() { return appComponent.schedulerProvider(); } … } } DaggerUserComponent (Generated)
  123. SUB COMPONENTS

  124. @ragdroid @droidconDE LOGIN SUBCOMPONENT

  125. @ActivityScope @Subcomponent(modules = arrayOf(LoginModule::class)) interface LoginComponent { @Subcomponent.Builder interface Builder

    { @BindsInstance fun loginActivity(loginActivity: LoginActivity): Builder } } LoginComponent
  126. @ActivityScope @Subcomponent(modules = arrayOf(LoginModule::class)) interface LoginComponent { @Subcomponent.Builder interface Builder

    { @BindsInstance fun loginActivity(loginActivity: LoginActivity): Builder } } LoginComponent
  127. @ActivityScope @Subcomponent(modules = arrayOf(LoginModule::class)) interface LoginComponent { @Subcomponent.Builder interface Builder

    { @BindsInstance fun loginActivity(loginActivity: LoginActivity): Builder } } LoginComponent
  128. @ActivityScope @Subcomponent(modules = arrayOf(LoginModule::class)) interface LoginComponent { @Subcomponent.Builder interface Builder

    { @BindsInstance fun loginActivity(loginActivity: LoginActivity): Builder } } LoginComponent
  129. @ActivityScope @Subcomponent(modules = arrayOf(LoginModule::class)) interface LoginComponent { @Subcomponent.Builder interface Builder

    { @BindsInstance fun loginActivity(loginActivity: LoginActivity): Builder } } LoginComponent
  130. @ragdroid @droidconDE LOGIN ACTIVITY

  131. class LoginActivity { private lateinit var loginComponent: LoginComponent override fun

    initDagger(appComponent: AppComponent) { loginComponent = appComponent .loginBuilder() .loginActivity(this) .build() } … } LoginActivity
  132. class LoginActivity { private lateinit var loginComponent: LoginComponent override fun

    initDagger(appComponent: AppComponent) { loginComponent = appComponent .loginBuilder() .loginActivity(this) .build() } … } LoginActivity
  133. @ragdroid @droidconDE DAGGER APP COMPONENT (Generated)

  134. public final class DaggerAppComponent implements AppComponent { private final class

    LoginComponentImpl implements LoginComponent { private LoginComponentImpl(LoginComponentBuilder builder) { assert builder != null; initialize(builder); } … } } DaggerAppComponent (Generated)
  135. public final class DaggerAppComponent implements AppComponent { private final class

    LoginComponentImpl implements LoginComponent { private LoginComponentImpl(LoginComponentBuilder builder) { assert builder != null; initialize(builder); } … } } DaggerAppComponent (Generated)
  136. public final class DaggerAppComponent implements AppComponent { private final class

    LoginComponentImpl implements LoginComponent { private LoginComponentImpl(LoginComponentBuilder builder) { assert builder != null; initialize(builder); } … } } DaggerAppComponent (Generated)
  137. @ragdroid @droidconDE SUB COMPONENT VS DEPENDENT COMPONENT

  138. <<interface>> AppComponent fun schedulerProvider() @Singleton

  139. DaggerAppComponent • schedulerProvider() : @Singleton • userManager : @Singleton LoginComponentImpl

    <<interface>> AppComponent fun schedulerProvider() @Singleton @ActivityScope
  140. DaggerAppComponent • schedulerProvider() : @Singleton • userManager : @Singleton LoginComponentImpl

    <<interface>> AppComponent fun schedulerProvider() Sub Component LoginComponent accesses any dependencies of DaggerAppComponent directly as inner class can access outer class members. @Singleton @ActivityScope
  141. DaggerUserComponent • schedulerProvider • pokemon DaggerAppComponent • schedulerProvider() : @Singleton

    • userManager : @Singleton LoginComponentImpl <<interface>> AppComponent fun schedulerProvider() HomeComponentImpl ItemsComponentImpl Dependent Component UserComponent accesses any dependencies of DaggerAppComponent via an interface of AppComponent. @Singleton @ActivityScope @UserScope @ActivityScope @ActivityScope Sub Component LoginComponent accesses any dependencies of DaggerAppComponent directly as inner class can access outer class members.
  142. DaggerUserComponent • schedulerProvider • pokemon DaggerAppComponent • schedulerProvider() : @Singleton

    • userManager : @Singleton LoginComponentImpl <<interface>> AppComponent fun schedulerProvider() HomeComponentImpl ItemsComponentImpl @Singleton @ActivityScope @UserScope @ActivityScope @ActivityScope Sub Component LoginComponent accesses any dependencies of DaggerAppComponent directly as inner class can access outer class members. Dependent Component UserComponent accesses any dependencies of DaggerAppComponent via an interface of AppComponent.
  143. @ragdroid @droidconDE Custom Scope Advantages • Dependency Lifecycle Management •

    Modularized code
  144. @ragdroid @droidconDE Some Limitations • Repetitive Injection code • Class

    knows about it’s Injector
  145. @ragdroid @droidconDE Some Limitations Dagger 2 Android

  146. INTERMEDIATE CONCEPTS “DEFEAT THE DAHAKA”

  147. @ragdroid @droidconDE @BINDS

  148. @Module public class AppModule { @Provides BaseSchedulerProvider providerSchedulerProvider(SchedulerProvider provider) {

    return provider; } } @Binds
  149. @Module public class AppModule { @Provides BaseSchedulerProvider providerSchedulerProvider(SchedulerProvider provider) {

    return provider; } } @Binds @Module public abstract class AppModule { @Binds abstract BaseSchedulerProvider providerSchedulerProvider(SchedulerProvider provider); }
  150. @ragdroid @droidconDE MULTIBINDING

  151. MultiBinding @IntoSet @Provides String - “Hello” @Provides String - “Hi”

    @Provides String - “How are you?”
  152. @Provides String - “Hello” @Provides String - “Hi” @Provides String

    - “How are you?” @IntoSet @IntoSet @IntoSet MultiBinding @IntoSet
  153. @Provides Set<String> {“Hello”, “Hi”, “How are you?”} MultiBinding @IntoSet

  154. MultiBinding @IntoMap <<interface>> Contract.Presenter MapPresenter JustPresenter TakePresenter

  155. MultiBinding @IntoMap @Provides MapPresenter mapPresenter @Provides JustPresenter justPresenter @Provides TakePresenter

    takePresenter
  156. MultiBinding @IntoMap @Provides MapPresenter mapPresenter @Provides JustPresenter justPresenter @Provides TakePresenter

    takePresenter @IntoMap @IntoMap @IntoMap
  157. MultiBinding @IntoMap @Provides MapPresenter mapPresenter @Provides JustPresenter justPresenter @Provides TakePresenter

    takePresenter @IntoMap @IntoMap @IntoMap @ClassKey(MapPresenter.java) @ClassKey(JustPresenter.java) @ClassKey(TakePresenter.java)
  158. MultiBinding @IntoMap @Provides Map<Class, Contract.Presenter> { mapPresenter, justPresenter, takePresenter }

  159. DAGGER 2 ANDROID “BEFRIEND THE BEAST”

  160. @ragdroid @droidconDE DAHAKA APPLICATION

  161. class DahakaApplication : Application(), HasActivityInjector { @Inject internal lateinit var

    activityInjector: DispatchingAndroidInjector<Activity> … override fun activityInjector(): AndroidInjector<Activity> { return activityInjector } … } DahakaApplication
  162. class DahakaApplication : Application(), HasActivityInjector { @Inject internal lateinit var

    activityInjector: DispatchingAndroidInjector<Activity> … override fun activityInjector(): AndroidInjector<Activity> { return activityInjector } … } DahakaApplication
  163. class DahakaApplication : Application(), HasActivityInjector { @Inject internal lateinit var

    activityInjector: DispatchingAndroidInjector<Activity> … override fun activityInjector(): AndroidInjector<Activity> { return activityInjector } … } DahakaApplication
  164. class DahakaApplication : Application(), HasActivityInjector { @Inject internal lateinit var

    activityInjector: DispatchingAndroidInjector<Activity> … override fun activityInjector(): AndroidInjector<Activity> { return activityInjector } … } DahakaApplication
  165. public interface HasActivityInjector { AndroidInjector<Activity> activityInjector(); } HasActivityInjector

  166. HasActivityInjector • A simple interface. • Implementing class “Has” ActivityInjector.

    public interface HasActivityInjector { AndroidInjector<Activity> activityInjector(); }
  167. DispatchingAndroidInjector : AndroidInjector

  168. DispatchingAndroidInjector : AndroidInjector • Injects members for Android types :

    Activity, Fragment, etc • Has a Map<Class, Provider<Factory>> injectorFactories.
  169. Provider<LoginActivitySubcomponent.Builder> LoginActivity.class Class<Activity> Provider<Factory<Activity>> DispatchingAndroidInject<Activity> • gets the Subcomponent.Builder from

    Map. • creates an instance using Builder. • calls component.inject(instance) to perform injections. • Injects members for Android types : Activity, Fragment, etc • Has a Map<Class, Provider<Factory>> injectorFactories. DispatchingAndroidInjector : AndroidInjector
  170. @ragdroid @droidconDE APP COMPONENT

  171. @Singleton @Component(modules = arrayOf(AppModule::class, ApiModule::class, AppBindingModule::class, AndroidSupportInjectionModule::class)) interface AppComponent :

    AndroidInjector<DaggerApplication> { … } AppComponent
  172. AppBindingModule @Singleton @Component(modules = arrayOf(AppModule::class, ApiModule::class, AppBindingModule::class, AndroidSupportInjectionModule::class)) interface AppComponent

    : AndroidInjector<DaggerApplication> { … } AppComponent
  173. @Module abstract class AppBindingModule { @ContributesAndroidInjector(modules = arrayOf(LoginModule::class)) @ActivityScope internal

    abstract fun loginActivity(): LoginActivity } AppBindingModule
  174. @ContributesAndroidInjector @Module abstract class AppBindingModule { @ContributesAndroidInjector(modules = arrayOf(LoginModule::class)) @ActivityScope

    internal abstract fun loginActivity(): LoginActivity } AppBindingModule
  175. @Module abstract class AppBindingModule { @ContributesAndroidInjector(modules = arrayOf(LoginModule::class)) @ActivityScope internal

    abstract fun loginActivity(): LoginActivity } AppBindingModule • If your Module is stateless. • If your Subcomponent.Builder is simple and doesn’t need to bind anything extra. • @ContributesAndroidInjector will generate the SubComponent for you. • No need to create LoginActivitySubcomponent class in the above case. @ContributesAndroidInjector AppBindingModule
  176. @Module abstract class AppBindingModule { @ContributesAndroidInjector(modules = arrayOf(LoginModule::class)) @ActivityScope internal

    abstract fun loginActivity(): LoginActivity } AppBindingModule @Module abstract class LoginModule { @Binds abstract fun provideLoginPresenter(loginPresenter: LoginPresenter): LoginContract.Presenter } LoginModule
  177. @Module(subcomponents = LoginActivitySubcomponent.class) public abstract class AppBindingModule_LoginActivity { @Binds @IntoMap

    @ActivityKey(LoginActivity.class) abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory( LoginActivitySubcomponent.Builder builder); @Subcomponent(modules = LoginModule.class) @ActivityScope public interface LoginActivitySubcomponent extends AndroidInjector<LoginActivity> { @Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<LoginActivity> {} } } LoginBindingModule(Generated)
  178. @Module(subcomponents = LoginActivitySubcomponent.class) public abstract class AppBindingModule_LoginActivity { @Binds @IntoMap

    @ActivityKey(LoginActivity.class) abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory( LoginActivitySubcomponent.Builder builder); @Subcomponent(modules = LoginModule.class) @ActivityScope public interface LoginActivitySubcomponent extends AndroidInjector<LoginActivity> { @Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<LoginActivity> {} } } LoginBindingModule(Generated)
  179. @Module(subcomponents = LoginActivitySubcomponent.class) public abstract class AppBindingModule_LoginActivity { @Binds @IntoMap

    @ActivityKey(LoginActivity.class) abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory( LoginActivitySubcomponent.Builder builder); @Subcomponent(modules = LoginModule.class) @ActivityScope public interface LoginActivitySubcomponent extends AndroidInjector<LoginActivity> { @Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<LoginActivity> {} } } LoginBindingModule(Generated)
  180. @Module(subcomponents = LoginActivitySubcomponent.class) public abstract class AppBindingModule_LoginActivity { @Binds @IntoMap

    @ActivityKey(LoginActivity.class) abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory( LoginActivitySubcomponent.Builder builder); @Subcomponent(modules = LoginModule.class) @ActivityScope public interface LoginActivitySubcomponent extends AndroidInjector<LoginActivity> { @Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder<LoginActivity> {} } } LoginBindingModule(Generated)
  181. @ragdroid @droidconDE LOGIN ACTIVITY

  182. public class LoginActivity { @Inject LoginContract.Presenter presenter; @Override protected void

    onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this); } } LoginActivity
  183. AndroidInjection.inject(LoginActivity) LoginActivity public class LoginActivity { @Inject LoginContract.Presenter presenter; @Override

    protected void onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this); } }
  184. AndroidInjection.inject(LoginActivity) AndroidInjection.inje

  185. AndroidInjection.inject(LoginActivity) AndroidInjection.inje AndroidInjection

  186. AndroidInjection.inject(LoginActivity) AndroidInjection.inje AndroidInjection DaggerAppComponent

  187. AndroidInjection.inject(LoginActivity) AndroidInjection.inje AndroidInjection DaggerAppComponent AppBindingModule_LoginActivity DispatchingAndroidInjector

  188. AndroidInjection.inject(LoginActivity) AndroidInjection.inje AndroidInjection DaggerAppComponent AppBindingModule_LoginActivity DispatchingAndroidInjector

  189. AndroidInjection.inject(LoginActivity) AndroidInjection.inje AndroidInjection DaggerAppComponent AppBindingModule_LoginActivity DispatchingAndroidInjector ApiModule_ProvideRetrofitFactory AppModule_ProviderSchedulerProviderFactory ApiModule_ProvidePokemonServiceFactory ApiModule_ProvideRetrofitFactory

    AppModule_ProviderSchedulerProviderFactory ApiModule_ProvidePokemonServiceFactory
  190. @ragdroid @droidconDE BEFRIEND THE BEAST “You can not change your

    fate, No droid can.”
  191. AndroidInjection.inject(LoginActivity)

  192. AndroidInjection.inject(LoginActivity) activity .getApplication() LoginActivity

  193. AndroidInjection.inject(LoginActivity) activity .getApplication() LoginActivity application .activityInjector() DahakaApplication : HasActivityInjector

  194. AndroidInjection.inject(LoginActivity) activity .getApplication() LoginActivity application .activityInjector() DahakaApplication : HasActivityInjector activityInjector

    .inject(activity) DispatchingAndroidInjector : AndroidInjector
  195. AndroidInjection.inject(LoginActivity) activity .getApplication() LoginActivity application .activityInjector() DahakaApplication : HasActivityInjector activityInjector

    .inject(activity) DispatchingAndroidInjector : AndroidInjector
  196. DispatchingAndroidInjector.inject(LoginActivity) injectorFactories .get(LoginActivity.class) DispatchingAndroidInjector : AndroidInjector

  197. DispatchingAndroidInjector : AndroidInjector Factory<LoginActivity> : LoginSubcomponent.Builder injectorFactories .get(LoginActivity.class) DispatchingAndroidInjector.inject(LoginActivity) builder

    .build()
  198. DispatchingAndroidInjector : AndroidInjector Factory<LoginActivity> : LoginSubcomponent.Builder component .inject(activity) LoginSubcomponent injectorFactories

    .get(LoginActivity.class) DispatchingAndroidInjector.inject(LoginActivity) builder .build()
  199. DispatchingAndroidInjector : AndroidInjector builder .build() Factory<LoginActivity> : LoginSubcomponent.Builder component .inject(activity)

    LoginSubcomponent DispatchingAndroidInjector.inject(LoginActivity) injectorFactories .get(LoginActivity.class)
  200. • DaggerApplication • DaggerActivity • DaggerBroadcastReceiver • DaggerContentProvider • DaggerFragment

    • DaggerIntentService • DaggerService Dagger Boilerplate classes
  201. Demo Code • Dahaka Demo : https://github.com/ragdroid/Dahaka • Branches :

    • dagger-android : Pokemon app using dagger-android (With Tests, Fragments) • dagger-android-dependent-comp : dagger-android with Dependent Component • dagger-android-dependent-comp-kotlin : In Kotlin • subcomponent : UserComponent as subcomponent • dependent-component : UserComponent as dependent component • dependent-component-kotlin : In Kotlin
  202. @ragdroid @droidconDE Dagger 2 Android = Dahaka • D •

    A • H • A • K • A Dagger Android HasActivityInjector AndroidInjection Keys AndroidInjector
  203. @ragdroid @droidconDE Dagger 2 Android “You can not change your

    fate, No droid can” Let’s befriend the beast instead.
  204. Acknowledgements • Dagger Recipies : Miroslaw Stanek (@froger_mcs) https://about.me/froger_mcs •

    todo-mvp-dagger : Mike Nakhimovich (@friendlyMikhail ) https://github.com/googlesamples/android-architecture/tree/todo-mvp-dagger • Android Dialogs : Mike Nakhimovich https://www.youtube.com/watch?v=KwRXQ6nT7jQ • Proof Reading : Ritesh Gupta (@_riteshhh) • Migrate to Kotlin : Ravindra Kumar (@ravidsrk)
  205. What Next? • Dagger Documentation : https://google.github.io/dagger// • todo-mvp-dagger :

    Mike Nakhimovich (@friendlyMikhail ) https://github.com/googlesamples/android-architecture/tree/todo-mvp-dagger • Dagger Example https://github.com/ragdroid/Dahaka • Testing article https://android.jlelse.eu/testing-your-app-with-dagger-2-c91cdc0860fb • Dagger and the Dahaka Series : https://medium.com/@ragdroid
  206. Other References • Theme : Prince of Persia https://en.wikipedia.org/wiki/Prince_of_Persia •

    Dahaka https://files.gamebanana.com/img/ico/sprays/dahaka.png • Dagger https://in.pinterest.com/pin/397442735844321339/ • Android http://www.pngmart.com/files/4/Android-PNG-Image.png
  207. @ragdroid @droidconDE CUT SCENES

  208. Dagger 2 Android “Defeat the Dahaka" Garima Jain @ragdroid

  209. Dagger 2 Android “Defeat the Dahaka" Garima Jain @ragdroid

  210. FUELED http://fueled.com/garima garima@fueled.com THANK YOU

  211. FUELED http://fueled.com/garima garima@fueled.com Q & A @ragdroid