koin

Project Url: Ekito/koin
Introduction: KOIN - a smart Kotlin dependency injection framework
More: Author   ReportBugs   
Tags:

logo

A pragmatic lightweight dependency injection framework for Kotlin developers.

Written in pure Kotlin, using functional resolution only: no proxy, no code generation, no reflection.

Koin is a DSL, a light container and a pragmatic API

Official Documentation now on https://insert-koin.io

All documentation, sample and references has been move to our website. Check the official website to get started: insert-koin.io. Koin samples project are located here: koin-samples

You can check the getting started section from our website, to discover Koin with the favorite platform. Or follow the snippets below.

Contact & Support

Follow us on Twitter for latest news: @insertkoin_io

Need help? Come on slack Koin channel from Kotlin slack. Or just open an issue on Github issues to share your problem.

Setup

Actual Version

koin_version = '0.9.3'

Gradle

Check that you have the jcenter repository.

// Add Jcenter to your repositories if needed
repositories {
    jcenter()    
}

Choose your the Koin module:

// Koin for Kotlin
compile "org.koin:koin-core:$koin_version"

// Koin for Android
compile "org.koin:koin-android:$koin_version"

// Koin for Android Architecture Components
compile "org.koin:koin-android-architecture:$koin_version"

// Koin for Spark Kotlin
compile "org.koin:koin-spark:$koin_version"

// Koin for Ktor Kotlin
compile "org.koin:koin-ktor:$koin_version"

// Koin for JUnit tests
testCompile "org.koin:koin-test:$koin_version"

Quickstart

Getting Started

Your first dependency with Android

Gradle

compile "org.koin:koin-android:$koin_version"

Declaring our first dependencies

Let's create a Repository to provide some data (giveHello()):

interface Repository {
    fun giveHello(): String
}

class MyRepository() : Repository {
    override fun giveHello() = "Hello Koin"
}

A Presenter class, for consuming this data:

// Use Repository - injected by constructor by Koin
class MyPresenter(val repository : Repository){
    fun sayHello() = repository.giveHello()
}

Use the applicationContext function to declare a module. Let's write our dependencies via constructor injection:

// Koin module
val myModule : Module = applicationContext {
    factory { MyPresenter(get()) } // get() will resolve Repository instance
    bean { MyRepository() as Repository }
}

By using the factory definition for our presenter, we will obtain a new instance each time we ask about the MyPresenter class.

Start Koin

Now that we have a module, let's start it with Koin. Open your application class, or make one (don't forget to declare it in your manifest.xml). Just call the startKoin() function:

class MyApplication : Application(){
    override fun onCreate() {
        super.onCreate()
        // Start Koin
        startKoin(this, listOf(myModule))
    }
}

Injecting dependencies

The MyPresenter component will be created with Repository instance. To get it from our Activity, let's inject it with the by inject() delegate injector (we can't directly create Activitiy instances from Koin):

class MyActivity : AppCompatActivity(){

    // Inject MyPresenter
    val presenter : MyPresenter by inject()

    override fun onCreate() {
        super.onCreate()
        // Let's use our presenter
        Log.i("MyActivity","presenter : ${presenter.sayHello()}")
    }
}

Your first dependency with Android ViewModel

Gradle

compile "org.koin:koin-android-architecture:$koin_version"

Declaring our first dependencies

Let's create a Repository to provide some data (giveHello()):

interface Repository {
    fun giveHello(): String
}

class MyRepository() : Repository {
    override fun giveHello() = "Hello Koin"
}

A ViewModel class, for consuming this data:

// Use Repository - injected by constructor by Koin
class MyViewModel(val repository : Repository) : ViewModel(){
    fun sayHello() = repository.giveHello()
}

Use the applicationContext function to declare a module. Let's write our dependencies via constructor injection:

// Koin module
val myModule : Module = applicationContext {
    viewModel { MyViewModel(get()) } // get() will resolve Repository instance
    bean { MyRepository() as Repository }
}

We are also using the viewModel keyword to declare an Android ViewModel component.

Start Koin

Now that we have a module, let's start it with Koin. Open your application class, or make one (don't forget to declare it in your manifest.xml). Just call the startKoin() function:

class MyApplication : Application(){
    override fun onCreate() {
        super.onCreate()
        // Start Koin
        startKoin(this, listOf(myModule))
    }
}

Injecting dependencies

The MyViewModel component will be created with Repository instance. To get it from our Activity, let's inject it with the by viewModel() delegate injector (we can't directly create Activitiy instances from Koin):

class MyActivity : AppCompatActivity(){

    // Inject MyViewModel
    val myViewModel : MyViewModel by viewModel()

    override fun onCreate() {
        super.onCreate()
        // Let's use our ViewModel
        Log.i("MyActivity","ViewModel : ${myViewModel.sayHello()}")
    }
}

Or if you want to eagerly create your ViewModel in a function, just use the getViewModel():

class MyActivity : AppCompatActivity(){

    override fun onCreate() {
        super.onCreate()

        val myViewModel : MyViewModel = getViewModel()

        // Let's use our ViewModel
        Log.i("MyActivity","ViewModel : ${myViewModel.sayHello()}")
    }
}

Unit Testing with Koin

Gradle Setup

First, add the Koin dependency like below:

// Add Jcenter to your repositories if needed
repositories {
    jcenter()    
}
dependencies {
    // Koin testing tools
    testcompile 'org.koin:koin-test:{{ site.current_version }}'
}

Declared dependencies

Let's create a Repository to provide some data (giveHello()):

interface Repository {
    fun giveHello(): String
}

class MyRepository() : Repository {
    override fun giveHello() = "Hello Koin"
}

A Presenter class, for consuming this data:

// Use Repository - injected by constructor by Koin
class MyPresenter(val repository : Repository){
    fun sayHello() = repository.giveHello()
}

Use the applicationContext function to declare a module. Let's declare our first component:

// Koin module
val myModule : Module = applicationContext {
    bean { MyPresenter(get()) } // get() will resolve Repository instance
    bean { MyRepository() as Repository }
}

Writing our first Test

To make our first test, let's write a simple Junit test file and extend it with KoinTest. We will be able then, to use by inject() operators.

class FirstTest : KoinTest {

    val presenter : MyPresenter by inject()
    val repository : Repository by inject()

    @Before
    fun before(){
        startKoin(listOf(myModule))
    }

    @After
    fun after(){
        closeKoin()
    }

    @Test
    fun testSayHello() {
        assertEquals(repository.giveHello(), presenter.sayHello())
    }
}

The KOIN DSL in 5 minutes

Keywords

A quick recap of the Koin DSL keywords:

  • applicationContext - create a Koin Module
  • factory - provide a factory bean definition
  • bean - provide a bean definition
  • bind - additional Kotlin type binding for given bean definition
  • get - resolve a component dependency
  • getProperty - resolve a property
  • context - declare a logical context

Special keywords:

  • viewModel - declare an Android ViewModel (koin-android-architecture only)
  • controller - declare a SparkJava controller (koin-spark only)

Deprecated: provide has been deprecated in favor to aliases. bean ~ provide and factory ~ provide(isSingleton=false)

Writing a module

Here below the Koin DSL keywords you need to know, to write your module. To declare a module, use the applicationContext function:

val myModule = applicationContext {
   // your dependencies here
}

The applicationContext lambda function is where you will write your definitions. myModule is the Koin module

To define your components, use the following keywords:

  • bean - define a singleton (create only one instance)
  • factory - define a factory (create a new instance each time)

Deprecated: provide keyword is now deprecated. Please use bean or factory

Below a simple definition of a MyRepository singleton:

class MyRepository()

val myModule = applicationContext {
   bean { MyRepository() }
}

Binding interfaces or several types

To bind a component with its interface, we have 2 solutions. Given an interface and its implmentation:

class MyRepositoryImpl()
interface MyRepository

We can write it:

  • bean { MyRepositoryImpl() as MyRepository } - will create an instance of type MyRepository
  • bean { MyRepositoryImpl() } bind MyRepository::class - will create an instance of type MyRepositoryImpl and will accept to bind on type MyRepository

*You can use the bind keyword with a class several times: bind Class1::class bind Class2::class

Multiple definitions of the same type

If you have mulitple definitions of the same type, Koin can't guess which instance to use. Then, you have to name each instance to clearly specify which instance to use. bean and factory have the name parameter (default parameter).

class MyLocalRepositoryImpl()
class MyRemoteRepositoryImpl()
interface MyRepository

we will write our module like:

val myModule = applicationContext {
   bean("local") { MyLocalRepositoryImpl() as  MyRepository }
   bean("remote") { MyRemoteRepositoryImpl() as  MyRepository }
}

Resolving a dependency

Koin push you to use constructor injection to bind your component. Given classes:

class ComponentA()
class ComponentB(val componentA : ComponentA)

We wil use the get() function to resolve a dependency:

val myModule = applicationContext {
   bean { ComponentA() }
   bean { ComponentB(get()) }
}

Using multiple modules / Module import

Every definition and module is lazy be default in Koin. This means that you can assemble several modules, by using the list of desired modules. Given some classes:

class ComponentA()
class ComponentB(val componentA : ComponentA)

And the two modules to declare it:

val myModule1 = applicationContext {
   bean { ComponentA() }
}
val myModule2 = applicationContext {
   bean { ComponentB(get()) }
}

Just start the module list together:

// Android Start
startKoin(this,listOf(module1,module2))
// Kotlin/Spark Start
startKoin(listOf(module1,module2))

Articles

Koin on Medium: Koin Developers Hub

Last articles

Support Me
Apps
About Me
Google+: Trinea trinea
GitHub: Trinea