Coder Social home page Coder Social logo

koin's Introduction

logo

What's KOIN?

A small library for writing dependency injection in a concise and pragmatic way. No proxy, no code generation, no introspection. Just DSL and functional Kotlin magic!

Declare, Start, Inject

Official website - https://insert-koin.io

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

Actual Version

koin_version = '0.9.1'

New features

  • DSL upgrade: now use the bean and factory keywords
  • Context scope isolation
  • Context callbacks - be notified when a context is release with registerContextCallBack()
  • Inject dynamic parameters into your definitions: bean { params -> MyPresenter(params["activity"])} and inject parameters with by inject(parameters=mapOf("activity" to ...))
  • viewModel & sharedViewModel

Table of Content

Getting Started

Koin Quick reference

Setup

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"

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

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

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

Your first SparkJava Controller with Koin

Gradle Setup

First, add the Koin dependency like below:

// Add Jcenter to your repositories if needed
repositories {
    jcenter()    
}
dependencies {
    // Koin for Kotlin apps
    compile 'org.koin:koin-spark:{{ site.current_version }}'
}

Service & Repository

Let's write our Service, a component that will ask Repository for data:

interface HelloService {
    fun sayHello(): String
}

class HelloServiceImpl(val helloRepository: HelloRepository) : HelloService {
    override fun sayHello() = "Hello ${helloRepository.getHello()} !"
}

and our Repository, which provide data:

interface HelloRepository {
    fun getHello(): String
}

class HelloRepositoryImpl : HelloRepository {
    override fun getHello(): String = "Spark & Koin"
}

Finally, we need an HTTP Controller to create the HTTP Route

class HelloController(val service: HelloService){
    init {
        get("/hello") {
            service.sayHello()
        }
    }
}

Declare your dependencies

Let's assemble our components with a Koin module:

val helloAppModule = applicationContext {
    bean { HelloServiceImpl(get()) as HelloService } // get() Will resolve HelloRepository
    bean { HelloRepositoryImpl() as HelloRepository }
    controller { HelloController(get()) } // get() Will resolve HelloService
}

Start and Inject

Finally, let's start Koin:

fun main(vararg args: String) {
    // Start Spark server & Koin with given modules
    start(modules = listOf(helloAppModule)) {
        // will run HelloController
        runControllers()
    }
}
The runControllers() instantiate any component declared with controller keyword.

That's it! You're ready to go.

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

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-architetcure 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))

Developer Guides

Android Developer Guide - Application samples about MVP & MVVM styles

Articles

Follow us

Twitter - @insertkoin_io

Slack - Kotlin Slack on #koin channel

koin's People

Contributors

amaksoft avatar elifarley avatar hvisser avatar jeevuz avatar lesraf avatar martin-g avatar michaelbarlow7 avatar wdoeland avatar wilder avatar zsmb13 avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.