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

@Inject Basics

Ce1ca64f3265f01a8718a622427f0a1d?s=47 Jitin
July 02, 2019

@Inject Basics

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

July 02, 2019
Tweet

More Decks by Jitin

Other Decks in Technology

Transcript

  1. @Inject Basics ! Jitin Sharma GO-JEK @_jitinsharma

  2. Dagger!

  3. None
  4. @Provides @Inject @Module @Component @Named @Singleton @Qaulifier @BindsInstance HasActivityInjector AndroidInjection

    @Subcomponent @ContributesAndroidInjector
  5. None
  6. None
  7. Dependency Injection What and Why @_jitinsharma

  8. Dependency injection is a technique whereby one object supplies the

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

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

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

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

  13. INVERSIOИ OF CONTROL @_jitinsharma

  14. DogActivity DogPresenter DogAPI DogRepository DogView

  15. DogActivity DogPresenter DogAPI DogRepository DogView Dependencies

  16. DogActivity DogPresenter DogAPI DogRepository DogView Dependencies

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

    get() = DogRepository() val presenter get() = DogPresenter()
  18. Dependency Container 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()
  19. 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() } }
  20. 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>() }
  21. Dependency Container class DogActivity : AppCompatActivity(), DogView { private val

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

  23. DogActivity DogPresenter DogAPI DogRepository DogView DependencyContainer

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

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

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

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

  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 DaggerCatComponent.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 DaggerCatComponent.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 DaggerCatComponent.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. DAGGER-ANDROID @_jitinsharma

  46. “screams in japanese”

  47. “screams in japanese”

  48. AndroidInjector Activity Fragment Service BrodcastReceiver ContentProvider Core Components

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

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

    bindDogActivity(): DogActivity ...
  51. @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)
  52. class DogActivity : AppCompatActivity(), DogView { @Inject lateinit var dogPresenter:

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

  54. Application Activity Fragment Service Content Provider Broadcast Receiver HasActivityInjector HasFragmentInjector

    HasServiceInjector HasBroadcastReceiverInjector HasContentProviderInjector HasFragmentInjector
  55. Application Activity Fragment Service Content Provider Broadcast Receiver HasActivityInjector HasFragmentInjector

    HasServiceInjector HasBroadcastReceiverInjector HasContentProviderInjector HasFragmentInjector
  56. class AnimalApp : Application(), HasActivityInjector { @Inject lateinit var dispatchingAndroidInjector:

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

    DispatchingAndroidInjector<Activity> override fun activityInjector(): AndroidInjector<Activity> = dispatchingAndroidInjector override fun onCreate() { super.onCreate() DaggerAppComponent.builder() .application(this) .build() .inject(this) ...
  58. class AnimalApp : Application(), HasActivityInjector { @Inject lateinit var dispatchingAndroidInjector:

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

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

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

    DogPresenter ... Support Module
  62. None
  63. KOTLIN @_jitinsharma

  64. Kotlin Delegation Lambda DSL

  65. KOIN @_jitinsharma

  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. Before software can be reusable it first has to be

    usable. Ralph Johnson
  81. - Koin - Kodein - Katana … … - RoboGuice

    - Dagger 1 - Dagger 2 Kotlin
  82. • https://jakewharton.com/helping-dagger-help-you/ • https://github.com/handstandsam/ShoppingApp Resources

  83. Danke schön @_jitinsharma