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. 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 • Scopes - “Face of the Dahaka” • @Singleton

    Scopes • @Reusable Scopes • Custom Scopes • Component Dependencies - “Unleash the Beast” • Dependent Component • Subcomponent • Dagger Android - “Befriend the Beast”
  5. 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)
  6. Provider 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)
  7. Provider • For each @Provides annotation dagger generates a Provider

    * • Dagger’s Factory<T> interface is also a Provider • Dagger has various implementations of Providers: • SingleCheck • DoubleCheck (javax.inject) * Not for unscoped dependencies - Coming up
  8. 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)
  9. 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)
  10. 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)
  11. 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)
  12. 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)
  13. 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)
  14. 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)
  15. AppModule @Module class AppModule(val application: Application) { @Provides //No @Singleton

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

    annotation fun provideApplication(): Application = application }
  17. DaggerAppComponent @Generated public final class DaggerAppComponent implements AppComponent { private

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

    has overheads. • By-default no Scope. • Scope only when needed • Like for Heavy Objects
  24. @Reusable • Limit the instantiation. • Use when Exact same

    instance not needed. • Can Have multiple sub-components caching different instances.
  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 and caching public T

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

    with State : @Singleton • Heavy immutable object / stateless : @Reusable • Not Heavy : No Scope •
  31. @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(); }
  32. @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(); }
  33. @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(); }
  34. @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(); }
  35. @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
  36. @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(); }
  37. @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)
  38. @ragdroid #chicagoroboto How to Improve? • Better Scope Management •

    More modularity • Custom Scopes : • @UserScope • @ActivityScope • @FragmentScope
  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 Log-Out jigglypuff Application
  40. class DahakaApplication : Application() { override fun onCreate() { super.onCreate()

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

    appComponent = DaggerAppComponent .builder() .application(this) .build() } } DahakaApplication
  42. @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
  43. @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
  44. @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
  45. public final class DaggerAppComponent implements AppComponent { private final class

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

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

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

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

    <<interface>> AppComponent fun schedulerProvider() @Singleton @ActivityScope
  50. 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
  51. 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.
  52. 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.
  53. class DahakaApplication : Application(), HasActivityInjector { @Inject internal lateinit var

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

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

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

    var activityInjector: DispatchingAndroidInjector<Activity> … override fun activityInjector(): AndroidInjector<Activity> { return activityInjector } … } DahakaApplication
  57. @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
  58. @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
  59. @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)
  60. @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)
  61. @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)
  62. @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)
  63. @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)
  64. public class LoginActivity { @Inject LoginContract.Presenter presenter; @Override protected void

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

    protected void onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this); } }
  66. HasActivityInjector • A simple interface. • Implementing class “Has” ActivityInjector.

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

    : DispatchingAndroidInjector<Activity> <<interface>> AndroidInjector<Activity> fun inject(Activity instance)
  68. 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)
  69. DispatchingAndroidInjector Provider<LoginActivitySubcomponent.Builder> LoginActivity.class Class<Activity> Provider<Subcomponent.Builder> DispatchingAndroidInject<Activity> • 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<Class, Provider<Subcomponent.Builder>> injectorFactories.
  70. DispatchingAndroidInjector : AndroidInjector builder .build() Factory<LoginActivity> : LoginSubcomponent.Builder component .inject(activity)

    LoginSubcomponent DispatchingAndroidInjector.inject(LoginActivity) injectorFactories .get(LoginActivity.class)
  71. @ragdroid #chicagoroboto Dagger 2 Android = Dahaka • D •

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

    fate, No droid can” Let’s befriend the beast instead.
  73. 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) } }
  74. LoginActivity public class LoginActivity { @Inject LoginContract.Presenter presenter; @Override protected

    void onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this); } }
  75. 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
  76. 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)
  77. 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
  78. 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