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

@Inject Basics - Droidcon India

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.

Jitin

November 03, 2019
Tweet

More Decks by Jitin

Other Decks in Programming

Transcript

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

    and have no relation to any twitter account. Disclaimer
  2. Setter Injection class Jitin { lateinit var stage: Stage fun

    setStage(stage: Stage) { this.stage = stage } !!...
  3. Constructor Injection class Jitin(private val stage: Stage, private var mic:

    Boolean = true) Jitin(stage = getStage(), mic = false) Jitin(stage = getStage())
  4. 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
  5. 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() } }
  6. 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>() }
  7. Dependency Container class DogActivity : AppCompatActivity(), DogView { private val

    dogPresenter by lazy { inject<DogPresenter>() } !!... override fun onCreate(savedInstanceState: Bundle?) { !!... DogDependencyContainer.init(this) !!...
  8. DogActivity DogPresenter DogAPI DogRepository DogView class DogRepository(private val dogApi: DogApi)

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

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

    dogPresenter by lazy { inject<DogPresenter>() } !!... override fun onCreate(savedInstanceState: Bundle?) { !!... DogDependencyContainer.init(this) !!...
  11. DogActivity DogPresenter DogAPI DogRepository DogView @Provides fun dogView(): DogView =

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

    constructor( private var dogView: DogView?, private val dogRepository: DogRepository ) Injecting Constructors
  13. Injecting Dependencies class MainActivity : AppCompatActivity(), DogView { @Inject lateinit

    var dogPresenter: DogPresenter override fun onCreate(savedInstanceState: Bundle?) { DaggerDogComponent.builder().dogModule(DogModule((this))).build().inject(this) } }
  14. 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
  15. Injection via code generation DaggerDogComponent!!... !..inject(this) DogActivity @Override public void

    inject(DogActivity dogActivity) { injectDogActivity(dogActivity); } DogActivity.kt DaggerDogComponent.java
  16. 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
  17. 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
  18. Scopes @Singleton @Component(modules = [AppModule!::class]) interface AppComponent { !!... @DogScope

    @Component(modules = [DogModule!::class], dependencies = [AppComponent!::class]) interface DogComponent { !!... DogComponent.kt AppComponent.kt
  19. @Module class DogModule { @Provides fun providesDogView(dogActivity: DogActivity): DogView =

    dogActivity !!... @Binds abstract fun provideDogView(dogActivity: DogActivity): DogView
  20. @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)
  21. class DogActivity : AppCompatActivity(), DogView { @Inject lateinit var dogPresenter:

    DogPresenter !!... override fun onCreate(savedInstanceState: Bundle?) { AndroidInjection.inject(this) !!...
  22. 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) !!...
  23. 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) !!...
  24. 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) !!...
  25. //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); }
  26. • A Dependency Injection Framework for Kotlin • Does not

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

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

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

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

    by inject { parametersOf(this) } private val imageLoader: ImageLoader by inject() !!... Injecting Members
  31. Modules and Scopes scope(named<CatActivity>()) { scoped { (catView: CatView) !->

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

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

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

    Facility of automatic constructors without using reflection