Slides from a talk and live-coding session about Koin, a pragmatic and lightweight Dependency Injection framework for Kotlin. This talk was given at Auckland Android Community on Dec 5.
https://www.meetup.com/Android-Meetup/events/256734688/
4. What is Koin?
• From insert-koin.io:
• A pragmatic lightweight dependency injection
framework for Kotlin developers.
5. What is Koin?
• From insert-koin.io:
• A pragmatic lightweight dependency injection
framework for Kotlin developers.
• Written in pure Kotlin, using functional resolution only:
no proxy, no code generation, no reflection.
6. What is Koin?
• From insert-koin.io:
• 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
8. What is Koin?
public class Person {
private String name;
private int age = 0;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (name != null ? !name.equals(person.name) : person.name != null) return false;
if (age != 0 ? age != person.age : person.age != 0) return false;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + ''' +
", age='" + age + ''' +
'}';
}
}
16. How does any of this work?
/**
* Create a Module
* Gather definitions
* @param path : Path of the module
* @param createOnStart : module definitions will be tagged as `createOnStart`
* @param override : allow all definitions from module to override definitions
*/
fun module(
path: String = Path.ROOT,
createOnStart: Boolean = false,
override: Boolean = false,
definition: ModuleDefinition.() -> Unit
): Module =
{ koinContext -> ModuleDefinition(path, createOnStart, override,
koinContext).apply(definition) }
org/koin/dsl/module/Module.kt
17. How does any of this work?
/**
* Create a Module
* Gather definitions
* @param path : Path of the module
* @param createOnStart : module definitions will be tagged as `createOnStart`
* @param override : allow all definitions from module to override definitions
*/
fun module(
path: String = Path.ROOT,
createOnStart: Boolean = false,
override: Boolean = false,
definition: ModuleDefinition.() -> Unit
): Module =
{ koinContext -> ModuleDefinition(path, createOnStart, override,
koinContext).apply(definition) }
org/koin/dsl/module/Module.kt
18. How does any of this work?
/**
* Create a Module
* Gather definitions
* @param path : Path of the module
* @param createOnStart : module definitions will be tagged as `createOnStart`
* @param override : allow all definitions from module to override definitions
*/
fun module(
path: String = Path.ROOT,
createOnStart: Boolean = false,
override: Boolean = false,
definition: ModuleDefinition.() -> Unit
): Module =
{ koinContext -> ModuleDefinition(path, createOnStart, override,
koinContext).apply(definition) }
org/koin/dsl/module/Module.kt
26. How does any of this work?
/**
* Create a Module
* Gather definitions
* @param path : Path of the module
* @param createOnStart : module definitions will be tagged as `createOnStart`
* @param override : allow all definitions from module to override definitions
*/
fun module(
path: String = Path.ROOT,
createOnStart: Boolean = false,
override: Boolean = false,
definition: ModuleDefinition.() -> Unit
): Module =
{ koinContext -> ModuleDefinition(path, createOnStart, override,
koinContext).apply(definition) }
org/koin/dsl/module/Module.kt
27. How does any of this work?
/**
* Create a Module
* Gather definitions
* @param path : Path of the module
* @param createOnStart : module definitions will be tagged as `createOnStart`
* @param override : allow all definitions from module to override definitions
*/
fun module(
path: String = Path.ROOT,
createOnStart: Boolean = false,
override: Boolean = false,
definition: ModuleDefinition.() -> Unit
): Module =
{ koinContext -> ModuleDefinition(path, createOnStart, override,
koinContext).apply(definition) }
org/koin/dsl/module/Module.kt
28. How does any of this work?
val postModule: Module = module(definition = {
single { PostPresenter(get()) }
})
29. How does any of this work?
val postModule: Module = module(definition = {
this.single { PostPresenter(get()) }
})
30. How does any of this work?
val postModule: Module = module(definition = {
this.single { PostPresenter(get()) }
})
32. How does any of this work?
/**
* Provide a single instance definition
* (unique instance)
*
* @param name
* @param createOnStart - need to be created at start
* @param override - allow definition override
* @param definition
*/
inline fun <reified T : Any> single(
name: String = "",
createOnStart: Boolean = false,
override: Boolean = false,
noinline definition: Definition<T>
): BeanDefinition<T> {
return provide(name, createOnStart, override, Kind.Single, definition)
}
org/koin/dsl/context/ModuleDefinition.kt
38. What about this?
/**
* Activity displaying the list of posts
*/
class PostActivity : AppCompatActivity(), PostView {
private val presenter: PostPresenter by inject()
// ...
39. What about this?
/**
* Activity displaying the list of posts
*/
class PostActivity : AppCompatActivity(), PostView {
private val presenter: PostPresenter by inject()
// ...
41. No magic
• Koin takes full advantage of Kotlin’s adv. language
features
42. No magic
• Koin takes full advantage of Kotlin’s adv. language
features
• E.g. reified generics, lambdas with receivers, type
inference
43. No magic
• Koin takes full advantage of Kotlin’s adv. language
features
• E.g. reified generics, lambdas with receivers, type
inference
• Less opaque/magical than annotation processing pipeline
for application developers
45. Testability?
// Just tag your class with KoinTest to unlock your testing power
class SimpleTest : KoinTest {
// lazy inject BusinessService into property
val service : BusinessService by inject()
@Test
fun myTest() {
// You can start your Koin configuration
startKoin(myModules)
// or directly get any instance
val service : BusinessService = get()
// Don't forget to close it at the end
closeKoin()
}
}
49. What about Scopes?
class MyScopeActivity : AppCompatActivity() {
// inject MyScopePresenter from "session" scope
val scopePresenter: MyScopePresenter by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_simple)
// bind "session" scope to component lifecycle
bindScope(getOrCreateScope("session"))
//...
}
}
52. Koin vs. Dagger overview
• Koin pros:
• Less boilerplate. Less arcane, easy to learn
53. Koin vs. Dagger overview
• Koin pros:
• Less boilerplate. Less arcane, easy to learn
• No annotation processing/code gen. Just language features
54. Koin vs. Dagger overview
• Koin pros:
• Less boilerplate. Less arcane, easy to learn
• No annotation processing/code gen. Just language features
• Straightforward Android integration
55. Koin vs. Dagger overview
• Koin pros:
• Less boilerplate. Less arcane, easy to learn
• No annotation processing/code gen. Just language features
• Straightforward Android integration
• Nice, simple documentation
56. Koin vs. Dagger overview
• Koin pros:
• Less boilerplate. Less arcane, easy to learn
• No annotation processing/code gen. Just language features
• Straightforward Android integration
• Nice, simple documentation
• Build speed (?)
57. Koin vs. Dagger overview
• Koin pros:
• Less boilerplate. Less arcane, easy to learn
• No annotation processing/code gen. Just language features
• Straightforward Android integration
• Nice, simple documentation
• Build speed (?)
• Koin cons:
58. Koin vs. Dagger overview
• Koin pros:
• Less boilerplate. Less arcane, easy to learn
• No annotation processing/code gen. Just language features
• Straightforward Android integration
• Nice, simple documentation
• Build speed (?)
• Koin cons:
• Runtime dependency resolution (though minimal overhead)
59. Koin vs. Dagger overview
• Koin pros:
• Less boilerplate. Less arcane, easy to learn
• No annotation processing/code gen. Just language features
• Straightforward Android integration
• Nice, simple documentation
• Build speed (?)
• Koin cons:
• Runtime dependency resolution (though minimal overhead)
• Newer, relatively unproven (compared to Dagger)
63. Is it Production-Ready?
• Research didn’t turn up much, but…
• Reached v1.0 in Sep (FWIW)
• The author uses it in several production apps…
64. Is it Production-Ready?
• Research didn’t turn up much, but…
• Reached v1.0 in Sep (FWIW)
• The author uses it in several production apps…
• Workable team uses it prod, details here: https://
medium.com/@charbgr/bye-bye-dagger-1494118dcd41