Kokain is pragmatic lightweight dependency injection framework for Kotlin based Applications. The Framework is reduced to the core functionalities of DI. Therefore the setup is pretty easy and producing nearly zero overhead.
easy to use - just annotate beans and start the framework on application start
no declaration of instance creation
possibility to safely inject activity context if bean injected by a activity hierarchy
different lifecycle scopes
lightweight implementation
pragmatic api
inject android context in a lifecycle aware matter
inject systemservices
buildscript {
repositories {
maven { url 'https://jitpack.io' }
}
}
...
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
apply plugin: 'kotlin-allopen'
apply plugin:"com.google.devtools.ksp"
.
.
.
implementation 'com.github.SchwarzIT.kokain:kokain-core-api:${latest_version}'
implementation 'com.github.SchwarzIT.kokain:kokain-core-lib:${latest_version}'
//for non android project use 'com.github.SchwarzIT.kokain:kokain-di-jvm' instead
implementation 'com.github.SchwarzIT.kokain:kokain-di:${latest_version}@aar'
// kapt plugin is the old fashion way and might be deleted in future releases use ksp plugin instead
//kapt 'com.github.SchwarzIT.kokain:kokain-processor:${latest_version}'
ksp "com.github.SchwarzIT.kokain:kokain-ksp:${kokain_version}"
.
.
.
allOpen {
annotation("com.schwarz.kokain.api.EBean")
}
@EBean
open class FooBean : FooBeanInterface {
private val mContext: Context by context()
private val mFooSingletonyBean : FooSingletonBean by inject()
override fun saySomething(): String {
return "something"
}
}
@EFactory(additionalFactories = [com.example.demolibrary.GeneratedFactory::class])
class DemoApplication : Application() {
override fun onCreate() {
super.onCreate()
KokainInstance.start(Kokain.create(GeneratedFactory(), this))
}
}
hint: For multimodule projects we need to add the GeneratedFactories for each module via the additionalFactories attribute
@EBean
class UsageOverview {
// no difference where the component comes from always use "by inject()"
private val mFooBean: FooBean by inject()
private val mSingletonBean: FooSingletonBean by inject()
private val mClassFromAnotherLibrary : ClassFromAnotherLibrary by inject()
// inject as Interface
private val mFooBeanInterface : FooBeanInterface by inject(FooBean::class)
// inject all sorts of systemservices
private val layoutInflater : LayoutInflater? by systemService()
//inject context (kokain injects activity context if it's save to do so otherwise it injects application context)
private val context : Context by context()
private fun doSomething(){
val bean = get<FooBean>()
bean.saySomething()
}
}
Example based on Mockk
1.) create a simple extension function
/**
* Sets up Kokain to use [mock] whenever an object of its type needs to be injected.
*/
inline fun <reified T : Any> Kokain.setMock(mock: T) {
every {
create<T>(any(), T::class)
} returns mock
}
2.) do some tests
class MySuperFancyControllerTest {
@RelaxedMockK
private lateinit var myBean1: BeanWithCode
@RelaxedMockK
lateinit var kokain: Kokain
@BeforeEach
fun setUp() {
kokain.setMock(myBean1)
KokainInstance.start(kokain)
}
@AfterEach
fun tearDown() {
KokainInstance.stop()
unmockkAll()
}
@Test
fun `do my test magic here without care about kokain`() {
}