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

Dagger 2 Android : Defeat the Dahaka DevFestND 2017

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

ragdroid

October 28, 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. @Singleton • Scope of dependency is throughout the application •

    Two ways to re-use dependencies : • Annotate Provider methods • Annotate the Dependency class itself (javax.inject)
  8. AppModule @Module public class AppModule { @Provides //No @Singleton annotation

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

    SomeDependency applicationProvider() { return new SomeDependency(); } }
  10. 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)
  11. 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)
  12. 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)
  13. 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)
  14. 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)); } }
  15. 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)); } }
  16. 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)
  17. 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)
  18. 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)
  19. Take Aways • DONT “Scope All the Things!” • Scoping

    has overheads. • By-default no Scope. • Scope only when needed • Like for Heavy Mutable Objects
  20. @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.
  21. 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)
  22. 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)
  23. 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)
  24. 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
  25. 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
  26. No Scope vs @Singleton vs @Reusable • Not Heavy :

    No Scope • Heavy mutable object : @Singleton • Heavy immutable object : @Reusable •
  27. @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(); }
  28. @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(); }
  29. @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(); }
  30. @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(); }
  31. @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
  32. @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(); }
  33. @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)
  34. @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
  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 @Component( modules = AppModule.class, ApiModule.class) @Module( includes = ApiModule.class) AppModule OR AppComponent
  36. @ragdroid @droidconDE How to Improve? • Better Scope Management •

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

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

    Component Items Component Login Component Home Component Items Component Fragments Fragments Launch Application
  39. 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
  40. 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
  41. 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
  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 Log-Out jigglypuff Inventory 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 Log-Out jigglypuff Inventory Inventory Application
  44. AppComponentImpl • schedulerProvider() : @Singleton • userManager : @Singleton LoginComponentImpl

    <<interface>> AppComponent schedulerProvider Login Sub Component @Singleton @ActivityScope
  45. 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
  46. 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
  47. @Singleton @Component(modules = arrayOf(AppModule::class, ApiModule::class)) interface AppComponent { fun loginBuilder():

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

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

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

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

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

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

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

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

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

    @Component.Builder interface Builder { @BindsInstance fun pokeMon(pokemon: Pokemon): Builder … } } UserComponent @BindsInstance
  61. @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
  62. @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
  63. @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
  64. 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)
  65. 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)
  66. 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)
  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. @ActivityScope @Subcomponent(modules = arrayOf(LoginModule::class)) interface LoginComponent { @Subcomponent.Builder interface Builder

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

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

    { @BindsInstance fun loginActivity(loginActivity: LoginActivity): Builder } } LoginComponent
  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. class LoginActivity { private lateinit var loginComponent: LoginComponent override fun

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

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

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

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

    LoginComponentImpl implements LoginComponent { private LoginComponentImpl(LoginComponentBuilder builder) { assert builder != null; initialize(builder); } … } } DaggerAppComponent (Generated)
  80. DaggerAppComponent • schedulerProvider() : @Singleton • userManager : @Singleton LoginComponentImpl

    <<interface>> AppComponent fun schedulerProvider() @Singleton @ActivityScope
  81. 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
  82. 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.
  83. 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.
  84. @Module public class AppModule { @Provides BaseSchedulerProvider providerSchedulerProvider(SchedulerProvider provider) {

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

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

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

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

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

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

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

    public interface HasActivityInjector { AndroidInjector<Activity> activityInjector(); }
  92. DispatchingAndroidInjector : AndroidInjector • Injects members for Android types :

    Activity, Fragment, etc • Has a Map<Class, Provider<Factory>> injectorFactories.
  93. 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
  94. @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
  95. @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
  96. @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)
  97. @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)
  98. @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)
  99. @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)
  100. public class LoginActivity { @Inject LoginContract.Presenter presenter; @Override protected void

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

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

    LoginSubcomponent DispatchingAndroidInjector.inject(LoginActivity) injectorFactories .get(LoginActivity.class)
  103. 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
  104. @ragdroid @droidconDE Dagger 2 Android = Dahaka • D •

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

    fate, No droid can” Let’s befriend the beast instead.
  106. 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)
  107. 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
  108. 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