Koin DSL

All the Koin DSL essentials

The KOIN DSL in 5 minutes

Below a short description on Koin DSL and how to write a module. For more detailed information please refer to the documentation.

Keywords

A quick recap of the Koin DSL keywords:

  • module { } - create a Koin Module or a submodule (inside a module)
  • factory { } - provide a factory bean definition
  • single { } - provide a bean definition
  • get() - resolve a component dependency
  • bind - additional Kotlin type binding for given bean definition
  • getProperty() - resolve a property

Writing a module

Given following classes:

class View(val presenter : Presenter)
interface Presenter
class MyPresenter(val repository : Repository) : Presenter
class DataRepository()

We can write it with a module:

val myModule = module {

    // Define a single instance of DataRepository
    single { DataRepository() }


    // define a submodule
    module("view"){

        // Define a factory for type Presenter (create a new instance each time)
        // Inject constructor with DataRepository
        factory<Presenter> { MyPresenter(get()) }
        
        // Define a single instance of View
        // Inject Presenter in constructor
        single { View(get()) }
    }
} 

Just start the module:

startKoin(listOf(myModule))

Definitions & types

Below, how you can specify type binding and definition.

Given the following classes/interfaces:

class MyPresenter() : Presenter
interface Presenter

We can declare definition with single or factory keywords.

Single type definition

To describe a singleton instance of MyPresenter, we can write it:

single { MyPresenter(get()) }

To describe a singleton instance of Presenter with MyPresenter implementation, we can write it:

single<Presenter> { MyPresenter(get()) }

Beware that those definitions will only match type Presenter.

Matching multiple types

We can describe a singleton instance of Presenter with MyPresenter implementation, while matching both types:

single { MyPresenter(get()) } bind Presenter::class

This definition will match types MyPresenter and Presenter. You can sepcify extra binding with bind operator, as much as you want.

Implicit naming & namespaces

If you don”t give a name to adefinition, Koin will give one related to its class name and path.

For example, the following factory MyPresenter can be resolved byts its name view.MyPresenter:

val myModule = module {
    
    module("view"){
        factory { MyPresenter() }
    }
} 

val presenter : MyPresenter = get(name = "view.MyPresenter")

Also convenient when you have several definition of the same type. You can resolve ComponentA with name B.ComponentA or C.ComponentA

module {
    module("B") {
        single { ComponentA() }
        single { ComponentB(get()) }
    }

    module("C") {
        single { ComponentA() }
        single { ComponentC(get()) }
    }
}

val a : ComponentA = get(name = "B.ComponentA")

You an aslo give a name to a definition, with the name attribute: single(name="aName") { ... }

Using and combining modules

There is no import features: all definitions are lazy and executed at runtime. This means that you can compose definitions with multiple modules. The above module can be separated:

 
val dataModule = module {

    // Define a single instance of DataRepository
    single<DataRepository>()
} 

// define module in /view path
val viewModule = module("view"){

    // Define a factory for type Presenter (create a new instance each time)
    // Inject constructor with DataRepository
    factory<Presenter> { create<MyPresenter>() }

    // Define a single instance of View
    // Inject Presenter in constructor
    single<View>()
}

Just start the module list:

startKoin(listOf(dataModule,viewModule))

Dealing with generics

Koin definitions doesn’t take in accounts generics type argument. For example, the module below tries to define 2 definitions of List:

module {
    single { ArrayList<Int>() }
    single { ArrayList<String>() }
}

Koin won’t start with such definitions, understanding that you want to override one definition for the other.

To allow you, use the 2 definitions you will have to differentiate them via their name, or location (module). For example:

module {
    single(name="Ints") { ArrayList<Int>() }
    single(name="Strings") { ArrayList<String>() }
}

Beyond Koin DSL

Below are some further readings: