Definitions

By using Koin, you describe definitions in modules. In this section we will see how to declare, organize & link your modules.

Writing a module

A Koin module is the space to declare all your components. Use the module function to declare a Koin module:

val myModule = module {
   // your dependencies here
}

In this module, you can declare components as decribed below.

Defining a singleton

Declaring a singleton component means that Koin container will keep a unique instance of your declared component. Use the single function in a module to declare a singleton:

class MyService()

val myModule = module {

    // declare single instance for MyService class
    single { MyService() }
}

Defining your component within a lambda

single, factory & scoped keywords help you declare your components through a lambda expression. this lambda describe the way that you build your component. Usually we instantiate components via their constructors, but you can also use any expression.

single { Class constructor // Kotlin expression }

The result type of your lambda is the main type of your component

Defining a factory

A factory component declaration is a definition that will gives you a new instance each time you ask for this definition (this instance is not retrained by Koin container, as it won’t inject this instance in other definitions later). Use the factory function with a lambda expression to build a component.

class Controller()

val myModule = module {

    // declare factory instance for Controller class
    factory { Controller() }
}
Note

Koin container doesn’t retain factory instances as it will give a new instance each time the definition is asked.

Resolving & injecting dependencies

Now that we can declare components definitions, we want to link instances with dependency injection. To resolve an instance in a Koin module, just use the get() function to the requested needed component instance. This get() function is usually used into constructor, to inject constructor values.

Important

To make dependency injection with Koin container, we have to write it in constructor injection style: resolve dependencies in class constructors. This way, your instance will be created with injected instances from Koin.

Let’s take an example with several classes:

// Presenter <- Service
class Service()
class Controller(val view : View)

val myModule = module {

    // declare Service as single instance
    single { Service() }
    // declare Controller as single instance, resolving View instance with get()
    single { Controller(get()) }
}

Definition: binding an interface

A single or a factory definition use the type from the their given lambda definition: i.e single { T } The matched type of the definition is the only matched type from this expression.

Let’s take an example with a class and implemented interface:

// Service interface
interface Service{

    fun doSomething()
}

// Service Implementation
class ServiceImp() : Service {

    fun doSomething() { ... }
}

In a Koin module we can use the as cast Kotlin operator as follow:

val myModule = module {

    // Will match type ServiceImp only
    single { ServiceImp() }

    // Will match type Service only
    single { ServiceImp() as Service }

}

You can also use the inferred type expression:

val myModule = module {

    // Will match type ServiceImp only
    single { ServiceImp() }

    // Will match type Service only
    single<Service> { ServiceImp() }

}
Note

This 2nd way of style declaration is preferred and will be used for the rest of the documentation.

Definition: binding an additional type

In some cases, we want to match several types from just one definition.

Let’s take an example with a class and interface:

// Service interface
interface Service{

    fun doSomething()
}

// Service Implementation
class ServiceImp() : Service{

    fun doSomething() { ... }
}

To make a definition bind additional types, we use the bind operator with a class:

val myModule = module {

    // Will match types ServiceImp & Service
    single { ServiceImp() } bind Service::class
}

Definition: naming & default bindings

You can specify a name to your definition, to help you distinguish two definitions about the same type:

Just request your definition with its name:

val myModule = module {
    single<Service>("default") { ServiceImpl() }
    single<Service>("test") { ServiceImpl() }
}

val service : Service by inject(name = "default")

get() and by inject() functions let you specify a definition name if needed.

By default Koin will bind a definition by its type or by its name, if the type is already bound to a definition.

val myModule = module {
    single<Service> { ServiceImpl1() }
    single<Service>("test") { ServiceImpl2() }
}

Then:

  • val service : Service by inject() will trigger the ServiceImpl1 definition

  • val service : Service by inject(name = "test") will trigger the ServiceImpl2 definition

Declaring injection parameters

In any single, factory or scope definition, you can use injection parameters: parameters that will be injected and used by your definition:

class Presenter(val view : View)

val myModule = module {
    single{ (view : View) -> Presenter(view) }
}

In contrary to resolved dependencies (resolved with with get()), injection parameters are parameters passed through the resolution API. This means that those parameters are values passed with get() and by inject(), with the parametersOf function:

val presenter : Presenter by inject { parametersOf(view) }

Further reading in the injection parameters section.

Using definition flags

Koin DSL also proposes some flags.

Create instances at start

A definition or a module can be flagged as createOnStart, to be created at start (or when you want). First set the createOnStart flag on your module or on your definition.

CreateAtStart flag on a definition
val myModuleA = module {

    single<Service> { ServiceImp() }
}

val myModuleB = module {

    // eager creation for this definition
    single<Service>(createAtStart=true) { TestServiceImp() }
}
CreateAtStart flag on a module
val myModuleA = module {

    single<Service> { ServiceImp() }
}

val myModuleB = module(createAtStart=true) {

    single<Service>{ TestServiceImp() }
}

The startKoin function will automatically create definitions instances flagged with createAtStart.

// Start Koin modules
startKoin {
    modules(myModuleA,myModuleB)
}
Note

if you need to load some definition at a special time (in a background thread instead of UI for example), just get/inject the desired components.

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>() }
}