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

@Inject Basics - Droidcon India

Ce1ca64f3265f01a8718a622427f0a1d?s=47 Jitin
November 03, 2019

@Inject Basics - Droidcon India

Dependency Injection is a concept which has become quite popular among Android developers as our applications break barriers on features and at the same time project complexity increases. It is also a heavily researched topic by developers with 20k questions on stack overflow(2k+ for dagger).
While most projects use dagger as a de-facto framework for Android, this talk would be more focussed on understanding concepts of DI and applying the same without a framework. We’ll go through concepts of supplying dependencies, various types of injection and understanding inversion of control. All of this without using a framework, with raw code in Kotlin and an actual android app with real life problems around networking, storage and threading.
We’ll then dig deep in how libraries like Dagger, Koin etc operate to provide the same with code generation or reflection.

Ce1ca64f3265f01a8718a622427f0a1d?s=128

Jitin

November 03, 2019
Tweet

More Decks by Jitin

Other Decks in Programming

Transcript

  1. @Inject Basics Jitin Sharma @_jitinsharma stages of dependency injection programming

  2. Dependency Injection Dagger Koin

  3. Why Dependency Injection

  4. Why Dependency Injection

  5. All opinions expressed in this talk are fictional in nature

    and have no relation to any twitter account. Disclaimer
  6. None
  7. Dependency injection is a technique whereby one object supplies the

    dependencies of another object
  8. Setter Injection class Jitin { lateinit var stage: Stage fun

    setStage(stage: Stage) { this.stage = stage } !!...
  9. Constructor Injection class Jitin(private val stage: Stage) { !!...

  10. Constructor Injection class Jitin(private val stage: Stage, private var mic:

    Boolean = true) Jitin(stage = getStage(), mic = false) Jitin(stage = getStage())
  11. Android Components - Activity - Application - Services - !!...

  12. INVERSIOИ OF CONTROL

  13. DogActivity DogPresenter DogAPI DogRepository DogView

  14. DogActivity DogPresenter DogAPI DogRepository DogView Dependencies

  15. DogActivity DogPresenter DogAPI DogRepository DogView Dependencies

  16. Dependency Container val dogApi: DogApi get() = ApiClient.dogClient.create(DogApi!::class.java) val dogRepository

    get() = DogRepository() val presenter get() = DogPresenter()
  17. object DogDependencyContainer { var dogView: DogView? = null fun init(dogView:

    DogView) { this.dogView = dogView } !!... val dogApi: DogApi get() = ApiClient.dogClient.create(DogApi!::class.java) val dogRepository get() = DogRepository() val presenter get() = DogPresenter() Dependency Container
  18. Dependency Container inline fun <reified T> inject(): T { return

    when (T!::class) { DogApi!::class !-> dogApi as T DogPresenter!::class !-> presenter as T DogRepository!::class !-> dogRepository as T DogView!::class !-> dogView as T else !-> throw DependencyNotFoundException() } }
  19. Dependency Container class DogPresenter { private val dogView by lazy

    { inject<DogView>() } private val dogRepository by lazy { inject<DogRepository>() } class DogRepository { private val dogApi by lazy { inject<DogApi>() }
  20. Dependency Container class DogActivity : AppCompatActivity(), DogView { private val

    dogPresenter by lazy { inject<DogPresenter>() } !!... override fun onCreate(savedInstanceState: Bundle?) { !!... DogDependencyContainer.init(this) !!...
  21. SERVICE LOCATOR

  22. DogActivity DogPresenter DogAPI DogRepository DogView DependencyContainer

  23. DogActivity DogPresenter DogAPI DogRepository DogView class DogRepository(private val dogApi: DogApi)

    class DogPresenter(private var dogView: DogView?, private val dogRepository: DogRepository) !// Interface DependencyContainer
  24. Dependency Container private val dogApi get() = ApiClient.dogClient.create(DogApi!::class.java) private val

    dogRepository get() = DogRepository(dogApi) val presenter get() = DogPresenter(dogView, dogRepository)
  25. Dependency Container class DogActivity : AppCompatActivity(), DogView { private val

    dogPresenter by lazy { inject<DogPresenter>() } !!... override fun onCreate(savedInstanceState: Bundle?) { !!... DogDependencyContainer.init(this) !!...
  26. None
  27. None
  28. None
  29. dagger

  30. @Inject javax.inject (JSR 330)

  31. @Inject javax.inject (JSR 330) @Provides @Provides !!...

  32. @Inject javax.inject (JSR 330) @Provides @Provides !!... @Module

  33. @Inject javax.inject (JSR 330) @Provides @Provides !!... @Module @Component

  34. DogActivity DogPresenter DogAPI DogRepository DogView @Provides fun dogView(): DogView =

    dogView @Provides fun dogApi(): DogApi = ApiClient.dogClient.create(DogApi!::class.java)
  35. class DogRepository @Inject constructor(private val dogApi: DogApi) class DogPresenter @Inject

    constructor( private var dogView: DogView?, private val dogRepository: DogRepository ) Injecting Constructors
  36. @Component(modules = [DogModule!::class]) interface DogComponent { fun inject(mainActivity: MainActivity) }

    Wiring up dependencies
  37. Injecting Dependencies class MainActivity : AppCompatActivity(), DogView { @Inject lateinit

    var dogPresenter: DogPresenter override fun onCreate(savedInstanceState: Bundle?) { DaggerDogComponent.builder().dogModule(DogModule((this))).build().inject(this) } }
  38. public final class DaggerDogComponent implements DogComponent { private DogRepository getDogRepository()

    { return new DogRepository(DogModule_DogApiFactory.dogApi(dogModule)); } private DogPresenter getDogPresenter() { return new DogPresenter(DogModule_DogViewFactory.dogView(dogModule), getDogRepository()); } !!... Component Generation
  39. Injection via code generation DaggerDogComponent!!... !..inject(this) DogActivity DogActivity.kt

  40. Injection via code generation DaggerDogComponent!!... !..inject(this) DogActivity @Override public void

    inject(DogActivity dogActivity) { injectDogActivity(dogActivity); } DogActivity.kt DaggerDogComponent.java
  41. Injection via code generation DaggerDogComponent!!... !..inject(this) DogActivity @Override public void

    inject(DogActivity dogActivity) { injectDogActivity(dogActivity); } public static void injectDogPresenter(DogActivity instance, DogPresenter dogPresenter) { instance.dogPresenter = dogPresenter; } DogActivity.kt DaggerDogComponent.java DogActivity_MembersInjector.java
  42. Injection via code generation DaggerDogComponent!!... !..inject(this) DogActivity @Override public void

    inject(DogActivity dogActivity) { injectDogActivity(dogActivity); } public static void injectDogPresenter(DogActivity instance, DogPresenter dogPresenter) { instance.dogPresenter = dogPresenter; } @Inject lateinit var dogPresenter: DogPresenter DogActivity.kt DaggerDogComponent.java DogActivity_MembersInjector.java
  43. Scopes @Singleton @Component(modules = [AppModule!::class]) interface AppComponent { !!... @DogScope

    @Component(modules = [DogModule!::class], dependencies = [AppComponent!::class]) interface DogComponent { !!... DogComponent.kt AppComponent.kt
  44. DaggerDogComponent.builder() .appComponent(appComponent) .dogModule(DogModule((this))) .build() .inject(this) Inversion of Control

  45. None
  46. dagger.android

  47. AndroidInjector Activity Fragment Service BrodcastReceiver ContentProvider Core Components

  48. @Module class DogModule { @Provides fun providesDogView(dogActivity: DogActivity): DogView =

    dogActivity !!... @Binds abstract fun provideDogView(dogActivity: DogActivity): DogView
  49. @Module abstract class BuildersModule { @ContributesAndroidInjector(modules = [DogModule!::class]) abstract fun

    bindDogActivity(): DogActivity !!...
  50. @Singleton @Component(modules = [AndroidInjectionModule!::class, AppModule!::class, BuildersModule!::class]) interface AppComponent { @Component.Builder

    interface Builder { @BindsInstance fun application(application: AnimalApp): Builder fun build(): AppComponent } fun inject(app: AnimalApp)
  51. class DogActivity : AppCompatActivity(), DogView { @Inject lateinit var dogPresenter:

    DogPresenter !!... override fun onCreate(savedInstanceState: Bundle?) { AndroidInjection.inject(this) !!...
  52. AndroidInjection.inject(this) Activity Fragment Service Content Provider Broadcast Receiver

  53. Application Activity Fragment Service Content Provider Broadcast Receiver HasAndroidInjector HasAndroidInjector

  54. Application Activity Fragment Service Content Provider Broadcast Receiver HasAndroidInjector HasAndroidInjector

  55. class AnimalApp : Application(), HasAndroidInjector { @Inject lateinit var dispatchingAndroidInjector:

    DispatchingAndroidInjector<Any> override fun androidInjector(): AndroidInjector<Any> = dispatchingAndroidInjector override fun onCreate() { super.onCreate() DaggerAppComponent.builder() .application(this) .build() .inject(this) !!...
  56. class AnimalApp : Application(), HasAndroidInjector { @Inject lateinit var dispatchingAndroidInjector:

    DispatchingAndroidInjector<Any> override fun androidInjector(): AndroidInjector<Any> = dispatchingAndroidInjector override fun onCreate() { super.onCreate() DaggerAppComponent.builder() .application(this) .build() .inject(this) !!...
  57. class AnimalApp : Application(), HasAndroidInjector { @Inject lateinit var dispatchingAndroidInjector:

    DispatchingAndroidInjector<Any> override fun androidInjector(): AndroidInjector<Any> = dispatchingAndroidInjector override fun onCreate() { super.onCreate() DaggerAppComponent.builder() .application(this) .build() .inject(this) !!...
  58. AppComponent Activity Modules Builder Module (@ContributesAndroidInjector) //Generated DaggerAppComponent SubComponent: AndroidInjector<>

    Provider Map<Class, Provider> DispatchingAndroidInjector
  59. //Generated DaggerAppComponent SubComponent: AndroidInjector<> Provider Map<Class, Provider> DispatchingAndroidInjector @Inject dispatchingAndroidInjector:

    DispatchingAndroidInjector<Any> Application class Activity Class AndroidInjection.inject(this) @Override public void inject(DogActivity arg0) { injectDogActivity(arg0); }
  60. class DogActivity : DaggerAppCompatActivity(), DogView { @Inject lateinit var dogPresenter:

    DogPresenter !!... Support Module
  61. None
  62. None
  63. KOTLIN

  64. Kotlin Delegation Lambda DSL

  65. KOIN

  66. • A Dependency Injection Framework for Kotlin • Does not

    use code generation • Works using Lambdas and Extensions KOIN
  67. val catModule = module { single<CatApi> { ApiClient.catClient.create(CatApi!::class.java) } single

    { CatRepository(get()) } factory { (catView: CatView) !-> CatPresenter(catView, get()) } } Module Declaration
  68. val catModule = module { single<CatApi> { ApiClient.catClient.create(CatApi!::class.java) } single

    { CatRepository(get()) } factory { (catView: CatView) !-> CatPresenter(catView, get()) } } Module Declaration
  69. Startup Configuration class AnimalApp : Application(){ override fun onCreate() {

    super.onCreate() startKoin { androidContext(this@AnimalApp) modules(listOf(catModule, dogModule, appModule)) } !!...
  70. class CatActivity : AppCompatActivity(), CatView { private val catPresenter: CatPresenter

    by inject { parametersOf(this) } private val imageLoader: ImageLoader by inject() !!... Injecting Members
  71. Load Modules BeanRegistry HashSet by inject()

  72. Load Modules BeanRegistry HashSet by inject() Service Locator

  73. Modules and Scopes unloadKoinModules(catModule) loadKoinModules(catModule) !// GlobalScope

  74. Modules and Scopes scope(named<CatActivity>()) { scoped { (catView: CatView) !->

    CatPresenter(catView, get()) } } CatPresenter by currentScope.inject { !!... LifeCycleOwner
  75. Modules and Scopes scope(named<CatActivity>()) { scoped { (catView: CatView) !->

    CatPresenter(catView, get()) } } CatPresenter by currentScope.inject { !!... LifeCycleOwner
  76. Koin has • Easy configuration • Drop in support for

    Android with ViewModels and Scopes • Excellent documentation and testing support
  77. Koin does not have • Strict Compile time safety •

    Facility of automatic constructors without using reflection
  78. Probably Yes Do you need Dependency Injection

  79. It Depends Do you need DI frameworks?

  80. Service Locator?

  81. HATERS GONNA HATE SERVICE LOCATORS GONNA LOCATE - 10x Engineer

  82. USE WHAT WORKS FOR YOU - 1x Engineer

  83. Thank You @_jitinsharma jitinsharma.in