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
- 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 @ github
- The essentials of Koin API for Android developer: Android Developer Quick Reference
You can check the getting started section from our website, to discover Koin with the favorite platform. Or follow the snippets below.
koin_version = '0.9.0'- DSL upgrade: now use the
beanandfactorykeywords - 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 withby inject(parameters=mapOf("activity" to ...))
Getting Started
- Your first dependency with Android
- Your first dependency with Android and ViewModel
- Your first SparkJava Controller with Koin
- Unit Testing with Koin
Koin Quick reference
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"compile "org.koin:koin-android:$koin_version"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.
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))
}
}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 create Activitiy instances):
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()}")
}
}compile "org.koin:koin-android-architecture:$koin_version"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.
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))
}
}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 create Activitiy instances):
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()}")
}
}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 }}'
}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 ceathe the HTTP Route
class HelloController(val service: HelloService){
init {
get("/hello") {
service.sayHello()
}
}
}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
}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()
}
}That's it! You're ready to go.
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 }}'
}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 }
}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())
}
}A quick recap of the Koin DSL keywords:
applicationContext- create a Koin Modulefactory- provide a factory bean definitionbean- provide a bean definitionbind- additional Kotlin type binding for given bean definitionget- resolve a component dependencygetProperty- resolve a propertycontext- declare a logical context
Deprecated: provide has been deprecated in favor to aliases. bean ~ provide and factory ~ provide(isSingleton=false)
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() }
}To bind a component with its interface, we have 2 solutions. Given an interface and its implmentation:
class MyRepositoryImpl()
interface MyRepositoryWe can write it:
bean { MyRepositoryImpl() as MyRepository }- will create an instance of typeMyRepositorybean { MyRepositoryImpl() } bind MyRepository::class- will create an instance of typeMyRepositoryImpland will accept to bind on typeMyRepository
*You can use the bind keyword with a class several times: bind Class1::class bind Class2::class
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 MyRepositorywe will write our module like:
val myModule = applicationContext {
bean("local") { MyLocalRepositoryImpl() as MyRepository }
bean("remote") { MyRemoteRepositoryImpl() as MyRepository }
}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()) }
}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))Below the Koin DSL keywords:
- declare component with
bean,factoryand a lmabda function to declare your component instance - Use
viewModel- to declare aViewModelcomponent (Android Architecture only) - Create a
contextto declare a logical context for a subset of components - resolve component with
get() - resolve Koin properties with
getProperty() - definition functions can use parameters:
bean { params -> MyPresenter(params["activity"])}
All your declared components are injected by constructor
Use startKoin() function to start Koin, from your Application class.
By default, Koin look at the assets/koin.properties file to load Properties.
You can also provide additional properties with startKoin function, with properties parameter.
Two ways of injecting your components:
- Components declared in Koin DSL, injection is made by constructor.
- Inside Android components classes (Activity,Fragment ...): use
by inject()by viewModel()- inject can handle dynamic parameters withparametersargument - By Tagging your class as
KoinComponent, you can unlockby inject()andreleaseContextfunctions
Below the Koin DSL keywords:
- declare component with
bean,factoryand a lmabda function to declare your component instance - Use the
controllerkeyword to declare a component with Spark HTTP routing - resolve component with
get() - resolve Koin properties with
getProperty()
All your declared components are injected by constructor
Use start() function to start Koin And Spark.
By default, Koin look at the resources/koin.properties file to load Properties.
You can also provide additional properties with start function, with properties parameter.
Components declared in Koin DSL, injection is made by constructor
- Koin release 0.8.0
- Push SparkJava to the next level (Kotlin Weekly issue 73, DZone.com )
- When Koin met Ktor ... (Kotlin Weekly issue 72)
- Moving from Dagger to Koin - Simplify your Android development - (Kotlin Weekly issue 66 & Android Weekly issue 282)
- Kotlin Weekly #64
- Insert Koin for dependency injection
- Better dependency injection for Android