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

Dagger 2 Android: Defeat the Dahaka

ragdroid
April 13, 2018

Dagger 2 Android: Defeat the Dahaka

ragdroid

April 13, 2018
Tweet

More Decks by ragdroid

Other Decks in Technology

Transcript

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

    View full-size slide

  2. @ragdroid
    #chicagoroboto
    POP QUIZ
    • Dagger2?
    • Dagger Android
    • Prince of Persia

    View full-size slide

  3. ABOUT THE TALK

    View full-size slide

  4. Theme: Prince of Persia
    • Prince uses Dagger
    • Dagger can reverse time
    • Dahaka, (guardian of timeline)
    • Dahaka comes to kill the Prince.

    View full-size slide

  5. Analogy
    • Prince = Us
    • Dagger = Dagger
    • Dahaka (Enemy) = Generated Code, Complexity

    View full-size slide

  6. Analogy
    • Developer uses Dagger
    • Developer starts backtracking the generated code
    • Developer is chased by the Dahaka (complexity of generated code)

    View full-size slide

  7. Agenda
    • Scopes - “Face of the Dahaka”
    • @Singleton Scopes
    • @Reusable Scopes
    • Custom Scopes
    • Component Dependencies - “Unleash the Beast”
    • Dependent Component
    • Subcomponent
    • Dagger Android - “Befriend the Beast”

    View full-size slide

  8. Who?
    Assumption : Basic familiarity with Dagger

    View full-size slide

  9. SCOPES
    “FACE OF THE DAHAKA”

    View full-size slide

  10. Scope
    How long a scoped instance lives
    (javax.inject)

    View full-size slide

  11. @Singleton
    Scope of dependency is throughout the application
    (javax.inject)

    View full-size slide

  12. @ragdroid
    #chicagoroboto
    @SINGLETON
    EXAMPLE

    View full-size slide

  13. AppComponent
    @Component(modules = [AppModule::class])
    @Singleton
    interface AppComponent {
    fun application(): Application
    }

    View full-size slide

  14. AppComponent
    @Component(modules = [AppModule::class])
    @Singleton
    interface AppComponent {
    fun application(): Application
    }

    View full-size slide

  15. @ragdroid
    #chicagoroboto
    CASE 1
    DEPENDENCY WITH SCOPE

    View full-size slide

  16. AppModule
    @Module
    class AppModule(val application: Application) {
    @Provides
    @Singleton
    fun provideApplication(): Application = application
    }

    View full-size slide

  17. AppModule
    @Module
    class AppModule(val application: Application) {
    @Provides
    @Singleton
    fun provideApplication(): Application = application
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  20. Provider
    • For each @Provides annotation dagger generates a Provider *
    • Dagger’s Factory interface is also a Provider
    • Dagger has various implementations of Providers:
    • SingleCheck
    • DoubleCheck
    (javax.inject)
    * Not for unscoped dependencies - Coming up

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  25. DoubleCheck
    Memoizes value using Double-Check idiom.
    (dagger.internal)

    View full-size slide

  26. 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)

    View full-size slide

  27. 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)

    View full-size slide

  28. 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)

    View full-size slide

  29. @ragdroid
    #chicagoroboto
    CASE 2
    DEPENDENCY W/O SCOPE

    View full-size slide

  30. AppModule
    @Module
    class AppModule(val application: Application) {
    @Provides //No @Singleton annotation
    fun provideApplication(): Application = application
    }

    View full-size slide

  31. AppModule
    @Module
    class AppModule(val application: Application) {
    @Provides //No @Singleton annotation
    fun provideApplication(): Application = application
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  35. DaggerAppComponent
    public final class DaggerAppComponent implements AppComponent {
    private AppModule appModule;
    @Override
    public Application application() {
    //No Factory Instance Creation
    return ApplicationFactory.proxyProviderApplication(appModule);
    }
    }
    (Generated)
    Since dagger 2.12

    View full-size slide

  36. DaggerAppComponent
    public final class DaggerAppComponent implements AppComponent {
    private AppModule appModule;
    @Override
    public Application application() {
    //No Factory Instance Creation
    return ApplicationFactory.proxyProviderApplication(appModule);
    }
    }
    (Generated)
    Since dagger 2.12

    View full-size slide

  37. DaggerAppComponent
    public final class DaggerAppComponent implements AppComponent {
    private AppModule appModule;
    @Override
    public Application application() {
    //No Factory Instance Creation
    return appModule.provideApplication();
    }
    }
    (Generated)
    Since dagger 2.12

    View full-size slide

  38. Take Aways
    • DONT “Scope All the Things!”
    • Scoping has overheads.
    • By-default no Scope.
    • Scope only when needed
    • Like for Heavy Objects

    View full-size slide

  39. @ragdroid
    #chicagoroboto
    CASE 3
    @REUSABLE

    View full-size slide

  40. @Reusable
    • Limit the instantiation.
    • Use when Exact same instance not needed.
    • Can Have multiple sub-components caching different instances.

    View full-size slide

  41. ReusableComponent

    @Component(modules = [ReusableModule::class])
    interface ReusableComponent {
    fun someObject(): SomeObject
    }

    View full-size slide

  42. ReusableComponent

    @Component(modules = [ReusableModule::class])
    interface ReusableComponent {
    fun someObject(): SomeObject
    }

    View full-size slide

  43. SomeObject
    @Reusable
    class SomeObject @Inject constructor()

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  47. SingleCheck
    Memoizes value using simple lazy initialization and caching
    (dagger.internal)

    View full-size slide

  48. Memoizes value using simple lazy initialization and caching
    public T get() {


    Provider providerReference = provider;

    if (instance == UNINITIALIZED) {

    instance = providerReference.get();

    provider = null;

    }

    return (T) instance;

    }
    (dagger.internal)
    SingleCheck

    View full-size slide

  49. Memoizes value using simple lazy initialization and caching
    public T get() {


    Provider providerReference = provider;

    if (instance == UNINITIALIZED) {

    instance = providerReference.get();

    provider = null;

    }

    return (T) instance;

    }
    (dagger.internal)
    SingleCheck

    View full-size slide

  50. @Singleton vs @Reusable vs No Scope
    • Heavy mutable object with State : @Singleton
    • Heavy immutable object / stateless : @Reusable
    • Not Heavy : No Scope


    View full-size slide

  51. @ragdroid
    #chicagoroboto
    GOD APP MODULE

    View full-size slide

  52. @ragdroid
    #chicagoroboto
    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();
    }

    View full-size slide

  53. @ragdroid
    #chicagoroboto
    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();
    }

    View full-size slide

  54. @ragdroid
    #chicagoroboto
    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();
    }

    View full-size slide

  55. @ragdroid
    #chicagoroboto
    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();
    }

    View full-size slide

  56. @ragdroid
    #chicagoroboto
    God App Module
    How To Improve?

    View full-size slide

  57. @ragdroid
    #chicagoroboto
    God App Module
    Splitting App Module

    View full-size slide

  58. @ragdroid
    #chicagoroboto
    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

    View full-size slide

  59. @ragdroid
    #chicagoroboto
    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();
    }

    View full-size slide

  60. @ragdroid
    #chicagoroboto
    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)

    View full-size slide

  61. @ragdroid
    #chicagoroboto
    Splitting App Module

    View full-size slide

  62. @ragdroid
    #chicagoroboto
    How to Improve?
    • Better Scope Management
    • More modularity
    • Custom Scopes :
    • @UserScope
    • @ActivityScope
    • @FragmentScope

    View full-size slide

  63. @ragdroid
    #chicagoroboto
    Custom Scopes

    View full-size slide

  64. @ragdroid
    #chicagoroboto
    Custom Scopes
    Multiple Components

    View full-size slide

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

    View full-size slide

  66. COMPONENT
    DEPENDENCIES

    View full-size slide

  67. @ragdroid
    #chicagoroboto
    SUB COMPONENT
    VS
    DEPENDENT COMPONENT

    View full-size slide

  68. 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
    Application

    View full-size slide

  69. AppComponent
    @Singleton
    DaggerAppComponent
    LoginComponent
    Sub Component
    @ActivityScope
    Dependent Component
    DaggerUserComponent
    • dependency
    HomeComponent
    ItemsComponent
    @UserScope

    View full-size slide

  70. @ragdroid
    #chicagoroboto
    APP COMPONENT

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  73. @ragdroid
    #chicagoroboto
    DAHAKA
    APPLICATION

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  76. DEPENDENT
    COMPONENTS

    View full-size slide

  77. @ragdroid
    #chicagoroboto
    USER
    COMPONENT

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  80. @ragdroid
    #chicagoroboto
    USER
    MANAGER

    View full-size slide

  81. @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

    View full-size slide

  82. @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

    View full-size slide

  83. @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

    View full-size slide

  84. @ragdroid
    #chicagoroboto
    DAGGER
    USER COMPONENT
    (Generated)

    View full-size slide

  85. public final class DaggerUserComponent implements UserComponent {

    }
    DaggerUserComponent (Generated)

    View full-size slide

  86. public final class DaggerUserComponent implements UserComponent {

    }
    DaggerUserComponent (Generated)

    View full-size slide

  87. SUB
    COMPONENTS

    View full-size slide

  88. @ragdroid
    #chicagoroboto
    LOGIN
    SUBCOMPONENT

    View full-size slide

  89. @ActivityScope
    @Subcomponent(modules = arrayOf(LoginModule::class))
    interface LoginComponent {
    ...
    }
    LoginComponent

    View full-size slide

  90. @ActivityScope
    @Subcomponent(modules = arrayOf(LoginModule::class))
    interface LoginComponent {
    ...
    }
    LoginComponent

    View full-size slide

  91. @ActivityScope
    @Subcomponent(modules = arrayOf(LoginModule::class))
    interface LoginComponent {
    ...
    }
    LoginComponent

    View full-size slide

  92. @ragdroid
    #chicagoroboto
    DAGGER
    APP COMPONENT
    (Generated)

    View full-size slide

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

    }
    }
    DaggerAppComponent(Generated)

    View full-size slide

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

    }
    }
    DaggerAppComponent(Generated)

    View full-size slide

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

    }
    }
    DaggerAppComponent(Generated)

    View full-size slide

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

    }
    }
    DaggerAppComponent(Generated)

    View full-size slide

  97. @ragdroid
    #chicagoroboto
    SUB COMPONENT
    VS
    DEPENDENT COMPONENT

    View full-size slide

  98. <>
    AppComponent
    fun schedulerProvider()
    @Singleton

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  101. DaggerUserComponent
    • schedulerProvider
    • pokemon
    DaggerAppComponent
    • schedulerProvider() : @Singleton
    • userManager : @Singleton
    LoginComponentImpl
    <>
    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.

    View full-size slide

  102. DaggerUserComponent
    • schedulerProvider
    • pokemon
    DaggerAppComponent
    • schedulerProvider() : @Singleton
    • userManager : @Singleton
    LoginComponentImpl
    <>
    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.

    View full-size slide

  103. @ragdroid
    #chicagoroboto
    Custom Scope Advantages
    • Dependency Lifecycle Management
    • Modularized code

    View full-size slide

  104. @ragdroid
    #chicagoroboto
    Some Limitations
    • Repetitive Injection code
    • Class knows about it’s Injector

    View full-size slide

  105. @ragdroid
    #chicagoroboto
    Some Limitations
    Dagger 2 Android

    View full-size slide

  106. DAGGER 2
    ANDROID
    “BEFRIEND THE BEAST”

    View full-size slide

  107. @ragdroid
    #chicagoroboto
    DAHAKA
    APPLICATION

    View full-size slide

  108. class DahakaApplication : Application(), HasActivityInjector {
    @Inject internal lateinit var
    activityInjector: DispatchingAndroidInjector

    override fun activityInjector(): AndroidInjector {
    return activityInjector
    }

    }
    DahakaApplication

    View full-size slide

  109. class DahakaApplication : Application(), HasActivityInjector {
    @Inject internal lateinit var
    activityInjector: DispatchingAndroidInjector

    override fun activityInjector(): AndroidInjector {
    return activityInjector
    }

    }
    DahakaApplication

    View full-size slide

  110. class DahakaApplication : Application(), HasActivityInjector {
    @Inject internal lateinit var
    activityInjector: DispatchingAndroidInjector

    override fun activityInjector(): AndroidInjector {
    return activityInjector
    }

    }
    DahakaApplication

    View full-size slide

  111. HasActivityInjector
    class DahakaApplication : Application(), HasActivityInjector {
    @Inject internal lateinit var
    activityInjector: DispatchingAndroidInjector

    override fun activityInjector(): AndroidInjector {
    return activityInjector
    }

    }
    DahakaApplication

    View full-size slide

  112. @ragdroid
    #chicagoroboto
    APP COMPONENT

    View full-size slide

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

    }
    AppComponent

    View full-size slide

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

    }
    AppComponent

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  117. @Module
    abstract class AppBindingModule {
    @ContributesAndroidInjector(modules = arrayOf(LoginModule::class))
    @ActivityScope
    internal abstract fun loginActivity(): LoginActivity
    }
    AppBindingModule
    No need to create LoginActivitySubcomponent class in the above case.
    @ContributesAndroidInjector
    AppBindingModule

    View full-size slide

  118. @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

    View full-size slide

  119. @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 {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder {}
    }
    }
    LoginBindingModule(Generated)

    View full-size slide

  120. @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 {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder {}
    }
    }
    LoginBindingModule(Generated)

    View full-size slide

  121. @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 {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder {}
    }
    }
    LoginBindingModule(Generated)

    View full-size slide

  122. @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 {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder {}
    }
    }
    LoginBindingModule(Generated)

    View full-size slide

  123. @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 {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder {}
    }
    }
    LoginBindingModule(Generated)

    View full-size slide

  124. @ragdroid
    #chicagoroboto
    LOGIN ACTIVITY

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  127. AndroidInjection.inject(LoginActivity)
    AndroidInjection.inje

    View full-size slide

  128. AndroidInjection.inject(LoginActivity)
    AndroidInjection.inje
    AndroidInjection

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  133. @ragdroid
    #chicagoroboto
    BEFRIEND THE BEAST
    “You can not change your fate,
    No droid can.”

    View full-size slide

  134. public interface HasActivityInjector {
    AndroidInjector activityInjector();
    }
    HasActivityInjector

    View full-size slide

  135. HasActivityInjector
    • A simple interface.
    • Implementing class “Has” ActivityInjector.
    public interface HasActivityInjector {
    AndroidInjector activityInjector();
    }

    View full-size slide

  136. HasActivityInjector
    <>
    HasActivityInjector
    fun activityInjector() :
    AndroidInjector

    View full-size slide

  137. HasActivityInjector
    <>
    HasActivityInjector
    fun activityInjector() :
    AndroidInjector
    DahakaApplication
    • activityInjector :
    DispatchingAndroidInjector

    View full-size slide

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

    View full-size slide

  139. HasActivityInjector
    <>
    HasActivityInjector
    fun activityInjector() :
    AndroidInjector
    DahakaApplication
    • activityInjector :
    DispatchingAndroidInjector
    DispatchingAndroidInjector
    • inject(Activity activity)
    • injectorFactories : Map
    <>
    AndroidInjector
    fun inject(Activity instance)

    View full-size slide

  140. DispatchingAndroidInjector
    Provider
    LoginActivity.class
    Class Provider
    DispatchingAndroidInject
    • gets the Subcomponent.Builder from injectorFactory.
    • creates an instance using Builder.
    • calls component.inject(instance) to perform injections.
    • Injects members for Android types : Activity, Fragment, etc
    • Has a Map> injectorFactories.

    View full-size slide

  141. AndroidInjection.inject(LoginActivity)

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  146. DispatchingAndroidInjector.inject(LoginActivity)
    injectorFactories
    .get(LoginActivity.class)
    DispatchingAndroidInjector : AndroidInjector

    View full-size slide

  147. DispatchingAndroidInjector : AndroidInjector
    Factory : LoginSubcomponent.Builder
    injectorFactories
    .get(LoginActivity.class)
    DispatchingAndroidInjector.inject(LoginActivity)
    builder
    .build()

    View full-size slide

  148. DispatchingAndroidInjector : AndroidInjector
    Factory : LoginSubcomponent.Builder
    component
    .inject(activity)
    LoginSubcomponent
    injectorFactories
    .get(LoginActivity.class)
    DispatchingAndroidInjector.inject(LoginActivity)
    builder
    .build()

    View full-size slide

  149. DispatchingAndroidInjector : AndroidInjector
    builder
    .build()
    Factory : LoginSubcomponent.Builder
    component
    .inject(activity)
    LoginSubcomponent
    DispatchingAndroidInjector.inject(LoginActivity)
    injectorFactories
    .get(LoginActivity.class)

    View full-size slide

  150. • DaggerApplication
    • DaggerActivity
    • DaggerBroadcastReceiver
    • DaggerContentProvider
    • DaggerFragment
    • DaggerIntentService
    • DaggerService
    Dagger Boilerplate classes

    View full-size slide

  151. @ragdroid
    #chicagoroboto
    Dagger 2 Android = Dahaka
    • D
    • A
    • H
    • A
    • K
    • A
    Dagger
    Android
    HasActivityInjector
    AndroidInjection
    Keys
    AndroidInjector

    View full-size slide

  152. @ragdroid
    #chicagoroboto
    Dagger 2 Android
    “You can not change your fate,
    No droid can”
    Let’s befriend the beast instead.

    View full-size slide

  153. @ragdroid
    #chicagoroboto
    LOGIN ACTIVITY

    View full-size slide

  154. AndroidInjection.inject(LoginActivity)
    LoginActivity
    public class LoginActivity {
    @Inject
    LoginContract.Presenter presenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    val appComponent = ((application as DahakaApplication)
    .appComponent)
    loginComponent = appComponent
    .loginBuilder()
    .loginActivity(this)
    .build()
    loginComponent.inject(this)
    }
    }

    View full-size slide

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

    View full-size slide

  156. 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

    View full-size slide

  157. 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)

    View full-size slide

  158. Demo Code
    • Dahaka Demo :
    https://github.com/ragdroid/Dahaka
    • Branches :
    • dagger-android : Pokemon app using dagger-android (With Tests, Fragments)
    • dagger-android-dependent-comp-kotlin : dagger-android with Dependent Component
    • subcomponent : UserComponent as subcomponent
    • dependent-component-kotlin : UserComponent as dependent component

    View full-size slide

  159. 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

    View full-size slide

  160. @ragdroid
    #chicagoroboto
    CUT
    SCENES

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  163. FUELED
    http://fueled.com/garima
    [email protected]
    THANK YOU

    View full-size slide

  164. FUELED
    http://fueled.com/garima
    [email protected]
    Q & A
    @ragdroid

    View full-size slide