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

Dagger 2 Android : Defeat the Dahaka

ragdroid
September 03, 2017

Dagger 2 Android : Defeat the Dahaka

Presentation for Droidcon Berlin, 2017.

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

ragdroid

September 03, 2017
Tweet

More Decks by ragdroid

Other Decks in Programming

Transcript

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

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

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

    generated code • Developer is chased by the Dahaka (complexity of generated code)
  4. 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”
  5. @ragdroid @droidconDE Dagger 1 Disadvantages • Reflection • Runtime Graph

    Composition • God Module with @Singleton • Difficult to use proguard
  6. @ragdroid @droidconDE Dagger 2 Advantages • No Reflection • Compile-time

    Graph Composition • Traceable code • Better Scope management
  7. Scope • Annotation from javax.inject package • How long a

    scoped instance lives • What happens if : • No Scope specified? • Annotation is specified?
  8. @Singleton • Another annotation from javax.inject package • Scope of

    dependency is throughout the application • Two ways to re-use dependencies : • Annotate Provider methods • Annotate the Dependency class itself
  9. AppModule @Module public class AppModule { private final Application application;

    public AppModule(Application application) { this.application = application; } @Provides //No @Singleton annotation Application applicationProvider() { return application; } }
  10. @Module public class AppModule { private final Application application; public

    AppModule(Application application) { this.application = application; } @Provides //No @Singleton annotation Application applicationProvider() { return application; } } AppModule
  11. DaggerAppComponent @Generated public final class DaggerAppComponent implements AppComponent { private

    Provider<Application> applicationProvider; /** other code **/ private void initialize(final Builder builder) { this.applicationProvider = AppModule_ApplicationFactory.create(builder.appModule); } } (Generated)
  12. DaggerAppComponent @Generated public final class DaggerAppComponent implements AppComponent { private

    Provider<Application> applicationProvider; /** other code **/ private void initialize(final Builder builder) { this.applicationProvider = AppModule_ApplicationFactory.create(builder.appModule); } } (Generated)
  13. DaggerAppComponent @Generated public final class DaggerAppComponent implements AppComponent { private

    Provider<Application> applicationProvider; /** other code **/ private void initialize(final Builder builder) { this.applicationProvider = AppModule_ApplicationFactory.create(builder.appModule); } } (Generated)
  14. AppModule @Module public class AppModule { private final Application application;

    public AppModule(Application application) { this.application = application; } @Provides @Singleton Application applicationProvider() { return application; } }
  15. AppModule @Module public class AppModule { private final Application application;

    public AppModule(Application application) { this.application = application; } @Provides @Singleton Application applicationProvider() { return application; } }
  16. DaggerAppComponent @Generated public final class DaggerAppComponent implements AppComponent { private

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

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

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

    Provider<Application> applicationProvider; /** other code **/ private void initialize(final Builder builder) { this.applicationProvider = DoubleCheck.provider( AppModule_ApplicationFactory.create(builder.appModule)); } } (Generated)
  20. 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)
  21. 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)
  22. 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)
  23. Take Aways • DONT “Scope All the Things!” • Scoping

    has overheads. • By-default no Scope. • Scope only when needed • Like for Heavy Mutable Objects
  24. @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.
  25. 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)
  26. 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)
  27. 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)
  28. 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
  29. Memoizes value using simple lazy initialization public T get() {


    
 Provider<T> providerReference = provider;
 if (instance == UNINITIALIZED) {
 instance = providerReference.get();
 provider = null;
 }
 return (T) instance;
 } (dagger.internal) SingleCheck
  30. @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(); }
  31. @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(); }
  32. @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(); }
  33. @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(); }
  34. @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
  35. @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(); }
  36. @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)
  37. @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
  38. @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
  39. @ragdroid @droidconDE How to Improve? • Better Scope Management •

    More modularity • Custom Scopes : • @UserScope • @ActivityScope • @FragmentScope
  40. AppComponent (@Singleton) UserComponent (@UserScope) UserComponent @UserScope Login Component @ActivityScope Home

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

    Component Items Component Login Component Home Component Items Component Fragments Fragments Launch Application
  42. 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
  43. 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
  44. 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
  45. 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
  46. 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
  47. AppComponentImpl • schedulerProvider() : @Singleton • userManager : @Singleton LoginComponentImpl

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

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

    • userManager : @Singleton LoginComponentImpl <<interface>> AppComponent schedulerProvider HomeComponentImpl ItemsComponentImpl Dependent Component Sub Component @Singleton @ActivityScope @UserScope @ActivityScope @ActivityScope
  50. @Singleton @Component(modules = arrayOf(AppModule::class, ApiModule::class)) interface AppComponent { fun loginBuilder():

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

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

    LoginComponent.Builder fun schedulerProvider(): BaseSchedulerProvider } AppComponent
  53. class DahakaApplication : Application() { override fun onCreate() { super.onCreate()

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

    appComponent = DaggerAppComponent .builder() .application(this) .build() } } DahakaApplication
  55. @Component(dependencies = arrayOf(AppComponent::class), modules = arrayOf(UserModule::class)) @UserScope interface UserComponent {

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

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

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

    to graph 1. UserModule Constructor 2. @Component.Builder with @BindsInstance
  59. 
 @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
  60. 
 @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
  61. 
 @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
  62. @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
  63. @Component(dependencies = arrayOf(AppComponent::class), modules = arrayOf(UserModule::class)) @UserScope interface UserComponent {

    @Component.Builder interface Builder { @BindsInstance fun pokeMon(pokemon: Pokemon): Builder … } } UserComponent @BindsInstance
  64. @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
  65. @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
  66. @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
  67. 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)
  68. 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)
  69. 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)
  70. 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)
  71. 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)
  72. 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)
  73. @ActivityScope @Subcomponent(modules = arrayOf(LoginModule::class)) interface LoginComponent { @Subcomponent.Builder interface Builder

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

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

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

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

    { @BindsInstance fun loginActivity(loginActivity: LoginActivity): Builder } } LoginComponent
  78. class LoginActivity { private lateinit var loginComponent: LoginComponent override fun

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

    initDagger(appComponent: AppComponent) { loginComponent = appComponent .loginBuilder() .loginActivity(this) .build() } … } LoginActivity
  80. public final class DaggerAppComponent implements AppComponent { this.loginBuilderProvider = new

    Factory<LoginComponent.Builder>() { @Override public LoginComponent.Builder get() { return new LoginComponentBuilder(); } }; } private final class LoginComponentBuilder implements LoginComponent.Builder { … } private final class LoginComponentImpl implements LoginComponent { private LoginComponentImpl(LoginComponentBuilder builder) { assert builder != null; initialize(builder); } … } } DaggerAppComponent (Generated)
  81. public final class DaggerAppComponent implements AppComponent { this.loginBuilderProvider = new

    Factory<LoginComponent.Builder>() { @Override public LoginComponent.Builder get() { return new LoginComponentBuilder(); } }; } private final class LoginComponentBuilder implements LoginComponent.Builder { … } private final class LoginComponentImpl implements LoginComponent { private LoginComponentImpl(LoginComponentBuilder builder) { assert builder != null; initialize(builder); } … } } DaggerAppComponent (Generated)
  82. public final class DaggerAppComponent implements AppComponent { this.loginBuilderProvider = new

    Factory<LoginComponent.Builder>() { @Override public LoginComponent.Builder get() { return new LoginComponentBuilder(); } }; } private final class LoginComponentBuilder implements LoginComponent.Builder { … } private final class LoginComponentImpl implements LoginComponent { private LoginComponentImpl(LoginComponentBuilder builder) { assert builder != null; initialize(builder); } … } } DaggerAppComponent (Generated)
  83. public final class DaggerAppComponent implements AppComponent { this.loginBuilderProvider = new

    Factory<LoginComponent.Builder>() { @Override public LoginComponent.Builder get() { return new LoginComponentBuilder(); } }; } private final class LoginComponentBuilder implements LoginComponent.Builder { … } private final class LoginComponentImpl implements LoginComponent { private LoginComponentImpl(LoginComponentBuilder builder) { assert builder != null; initialize(builder); } … } } DaggerAppComponent (Generated)
  84. public final class DaggerAppComponent implements AppComponent { this.loginBuilderProvider = new

    Factory<LoginComponent.Builder>() { @Override public LoginComponent.Builder get() { return new LoginComponentBuilder(); } }; } private final class LoginComponentBuilder implements LoginComponent.Builder { … } private final class LoginComponentImpl implements LoginComponent { private LoginComponentImpl(LoginComponentBuilder builder) { assert builder != null; initialize(builder); } … } } DaggerAppComponent (Generated)
  85. public final class DaggerAppComponent implements AppComponent { this.loginBuilderProvider = new

    Factory<LoginComponent.Builder>() { @Override public LoginComponent.Builder get() { return new LoginComponentBuilder(); } }; } private final class LoginComponentBuilder implements LoginComponent.Builder { … } private final class LoginComponentImpl implements LoginComponent { private LoginComponentImpl(LoginComponentBuilder builder) { assert builder != null; initialize(builder); } … } } DaggerAppComponent (Generated)
  86. public final class DaggerAppComponent implements AppComponent { this.loginBuilderProvider = new

    Factory<LoginComponent.Builder>() { @Override public LoginComponent.Builder get() { return new LoginComponentBuilder(); } }; } private final class LoginComponentBuilder implements LoginComponent.Builder { … } private final class LoginComponentImpl implements LoginComponent { private LoginComponentImpl(LoginComponentBuilder builder) { assert builder != null; initialize(builder); } … } } DaggerAppComponent (Generated)
  87. DaggerAppComponent • schedulerProvider() : @Singleton • userManager : @Singleton LoginComponentImpl

    <<interface>> AppComponent fun schedulerProvider() @Singleton @ActivityScope
  88. 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
  89. 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.
  90. 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.
  91. @Module public class AppModule { @Provides BaseSchedulerProvider providerSchedulerProvider(SchedulerProvider provider) {

    return provider; } } @Binds @Module public abstract class AppModule { @Binds abstract BaseSchedulerProvider providerSchedulerProvider(SchedulerProvider provider); }
  92. @Provides String - “Hello” @Provides String - “Hi” @Provides String

    - “How are you?” @IntoSet @IntoSet @IntoSet MultiBinding @IntoSet
  93. MultiBinding @IntoMap @Provides MapPresenter mapPresenter @Provides JustPresenter justPresenter @Provides TakePresenter

    takePresenter @IntoMap @IntoMap @IntoMap @ClassKey(MapPresenter.java) @ClassKey(JustPresenter.java) @ClassKey(TakePresenter.java)
  94. class DahakaApplication : Application(), HasActivityInjector { @Inject internal lateinit var

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

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

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

    activityInjector: DispatchingAndroidInjector<Activity> … override fun activityInjector(): AndroidInjector<Activity> { return activityInjector } … } DahakaApplication
  98. HasActivityInjector • A simple interface. • Implementing class “Has” ActivityInjector.

    • ActivityInjector = AndroidInjector<Activity>. public interface HasActivityInjector { AndroidInjector<Activity> activityInjector(); }
  99. HasActivityInjector <<interface>> HasActivityInjector fun activityInjector() : AndroidInjector<Activity> DahakaApplication • activityInjector

    : DispatchingAndroidInjector<Activity> <<interface>> AndroidInjector<Activity> fun inject(Activity instance)
  100. HasActivityInjector <<interface>> HasActivityInjector fun activityInjector() : AndroidInjector<Activity> DahakaApplication • activityInjector

    : DispatchingAndroidInjector<Activity> DispatchingAndroidInjector<Activity> • inject(Activity activity) • injectorFactories : Map <<interface>> AndroidInjector<Activity> fun inject(Activity instance)
  101. DispatchingAndroidInjector • Injects members for Android types : Activity, Fragment,

    etc • Has a Map<Class, Provider<Factory>> injectorFactories.
  102. DispatchingAndroidInjector 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.
  103. Provider<HomeActivitySubcomponent.Builder> HomeActivity.class ItemsActivity.class Provider<ItemsActivitySubcomponent.Builder> Provider<ProfileFragmentSubcomponent.Builder> ProfileFragment.class MovesFragment.class Provider<MovesFragmentSubcomponent.Builder> Class<Fragment> Provider<Factory<Fragment>>

    Provider<StatsFragmentSubcomponent.Builder> StatsFragment.class DispatchingAndroidInjector Provider<LoginActivitySubcomponent.Builder> LoginActivity.class Class<Activity> Provider<Factory<Activity>> DispatchingAndroidInject<Activity> DispatchingAndroidInject<Fragment>
  104. @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
  105. @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
  106. @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)
  107. @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)
  108. @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)
  109. @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)
  110. @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)
  111. @Beta @Module(includes = AndroidInjectionModule.class) public abstract class AndroidSupportInjectionModule { @Multibinds

    abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>> supportFragmentInjectorFactories(); private AndroidSupportInjectionModule() {} } @Beta @Module public abstract class AndroidInjectionModule { @Multibinds abstract Map<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>> activityInjectorFactories(); @Multibinds abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>> fragmentInjectorFactories(); … } AndroidSupportInjectionModule (dagger.android)
  112. @Beta @Module(includes = AndroidInjectionModule.class) public abstract class AndroidSupportInjectionModule { @Multibinds

    abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>> supportFragmentInjectorFactories(); private AndroidSupportInjectionModule() {} } @Beta @Module public abstract class AndroidInjectionModule { @Multibinds abstract Map<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>> activityInjectorFactories(); @Multibinds abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>> fragmentInjectorFactories(); … } AndroidSupportInjectionModule (dagger.android)
  113. @Beta @Module(includes = AndroidInjectionModule.class) public abstract class AndroidSupportInjectionModule { @Multibinds

    abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>> supportFragmentInjectorFactories(); private AndroidSupportInjectionModule() {} } @Beta @Module public abstract class AndroidInjectionModule { @Multibinds abstract Map<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>> activityInjectorFactories(); @Multibinds abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>> fragmentInjectorFactories(); … } AndroidSupportInjectionModule (dagger.android)
  114. @Beta @Module(includes = AndroidInjectionModule.class) public abstract class AndroidSupportInjectionModule { @Multibinds

    abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>> supportFragmentInjectorFactories(); private AndroidSupportInjectionModule() {} } @Beta @Module public abstract class AndroidInjectionModule { @Multibinds abstract Map<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>> activityInjectorFactories(); @Multibinds abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>> fragmentInjectorFactories(); … } AndroidSupportInjectionModule (dagger.android)
  115. @Beta @Module(includes = AndroidInjectionModule.class) public abstract class AndroidSupportInjectionModule { @Multibinds

    abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>> supportFragmentInjectorFactories(); private AndroidSupportInjectionModule() {} } @Beta @Module public abstract class AndroidInjectionModule { @Multibinds abstract Map<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>> activityInjectorFactories(); @Multibinds abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>> fragmentInjectorFactories(); … } AndroidSupportInjectionModule (dagger.android)
  116. public class LoginActivity { @Inject LoginContract.Presenter presenter; @Override protected void

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

    protected void onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this); } }
  118. DispatchingAndroidInjector : AndroidInjector builder .build() Factory<LoginActivity> : LoginSubcomponent.Builder component .inject(activity)

    LoginSubcomponent DispatchingAndroidInjector.inject(LoginActivity) injectorFactories .get(LoginActivity.class)
  119. public class LoginActivity { @Inject LoginContract.Presenter presenter; @Override protected void

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

    onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this); } } LoginActivity
  121. @Module public class TestLoginModule { @Mock LoginPresenter loginPresenter; public TestLoginModule()

    { MockitoAnnotations.initMocks(this); } @Provides @ActivityScope public LoginContract.Presenter provideLoginPresenter() { return loginPresenter; } } TestLoginModule
  122. @Module public class TestLoginModule { @Mock LoginPresenter loginPresenter; public TestLoginModule()

    { MockitoAnnotations.initMocks(this); } @Provides @ActivityScope public LoginContract.Presenter provideLoginPresenter() { return loginPresenter; } } TestLoginModule
  123. @Module public class TestLoginModule { @Mock LoginPresenter loginPresenter; public TestLoginModule()

    { MockitoAnnotations.initMocks(this); } @Provides @ActivityScope public LoginContract.Presenter provideLoginPresenter() { return loginPresenter; } } TestLoginModule
  124. 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
  125. @ragdroid @droidconDE Dagger 2 Android = Dahaka • D •

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

    fate, No droid can” Let’s befriend the beast instead.
  127. 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)
  128. 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 • Android Dialogs : Mike Nakhimovich https://www.youtube.com/watch?v=KwRXQ6nT7jQ • 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
  129. 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