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

@Inject Basics

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.

Jitin

July 02, 2019
Tweet

More Decks by Jitin

Other Decks in Technology

Transcript

  1. Setter Injection class Jitin { lateinit var stage: Stage fun

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

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

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

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

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

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

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

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

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

    inject(DogActivity dogActivity) { injectDogActivity(dogActivity); } DogActivity.kt DaggerCatComponent.java
  15. 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
  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; } @Inject lateinit var dogPresenter: DogPresenter DogActivity.kt DaggerCatComponent.java DogActivity_MembersInjector.java
  17. Scopes @Singleton @Component(modules = [AppModule::class]) interface AppComponent { ... @DogScope

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

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

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

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

    HasServiceInjector HasBroadcastReceiverInjector HasContentProviderInjector HasFragmentInjector
  23. 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) ...
  24. 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) ...
  25. 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) ...
  26. //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); }
  27. • A Dependency Injection Framework for Kotlin • Does not

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

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

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

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

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

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

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

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

    Facility of automatic constructors without using reflection
  36. - Koin - Kodein - Katana … … - RoboGuice

    - Dagger 1 - Dagger 2 Kotlin