Koin
The Koin library allows you to implement dependency injection (DI) scenarios in a Kotlin application.
Steps to use Koin:
- define interface of some service
- define implementation of that service
- add implementation of service to the koin module
- start koin with specified modules
- use DI where you need
You can define several configurations with different modules. You can define all modules in single file, for example, Modules.kt.
gradle dependencies
dependencies {
def koin_version = "3.4.2"
// compile "io.insert-koin:koin-core:$koin_version"
// testCompile "io.insert-koin:koin-test:$koin_version"
// Koin main features for Android
implementation "io.insert-koin:koin-android:$koin_version"
// Java Compatibility
// implementation "io.insert-koin:koin-android-compat:$koin_version"
// Jetpack WorkManager
// implementation "io.insert-koin:koin-androidx-workmanager:$koin_version"
// Navigation Graph
// implementation "io.insert-koin:koin-androidx-navigation:$koin_version"
// Jetpack Compose
// implementation "io.insert-koin:koin-androidx-compose:$koin_version"
// for using kTor
// implementation("io.insert-koin:koin-ktor:$koin_version")
// SLF4J Logger
// implementation "io.insert-koin:koin-logger-slf4j:$koin_version"
// for using JUnit 5
// testImplementation("io.insert-koin:koin-test-junit5:$koin_version")
}
declare modules
Modules are declared via Koin DSL.
Typically, module components are singletons, but they don't have to be. For example, view models in android.
One component of module can depend from other component of same or other module. For example, in the code below, the HelloServiceImpl service depends on the HelloMessageData object. In such cases, use the get() method to create the dependency object in the module.
Let's we have following data class, service interface ind its implementation.
class HelloMessageData {
val message: String = "Hello Koin!"
}
interface HelloService {
fun hello(): String
}
class HelloServiceImpl(private val helloMessageData: HelloMessageData) : HelloService {
override fun hello() = "Hey, ${helloMessageData.message}"
}
You can then declare a module like this
val helloModule = module {
single { HelloMessageData() }
single { HelloServiceImpl(get()) as HelloService }
}
val helloModule = module {
singleOf(::HelloMessageData)
singleOf(::HelloServiceImpl) { bind<HelloService>() }
}
start koin
fun main(vararg args: String) {
startKoin {
modules(helloModule)
}
// ...
}
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@MyApplication)
modules(helloModule)
}
}
}
injection
The KoinComponent interface denotes that object will use DI. It is not necessary for Activity classes on Android platform.
Components of modules can use the injection in constructor.
// Controller & HelloService are declared in a module
class Controller(val service: HelloService) {
fun hello() {
// service is ready to use
service.sayHello()
}
}
// Add KoinComponent interface to class.
class HelloApplication : KoinComponent {
// Inject HelloService
val helloService by inject<HelloService>()
// ...
}
class MyActivity() : AppCompatActivity() {
// inject HelloService into property
val service: HelloService by inject()
// ...
}
android viewmodel
For the Android platform, Koin allows you to inject view models.
1.First declare the viewmodel in the koin module like
/* let viewmodel
class AuthViewModel(
private val authPreferences: AuthPreferences
) : ViewModel() { ... }*/
val authModule = module {
single { AuthPreferences(CustomApplication.application) }
viewModel { AuthViewModel(get()) }
}
2. Inject viewmodel into activities and fragments.
// Inject into activity
class MainActivity : AppCompatActivity() {
// don't confuse with by viewModels()
private val viewModel: UserViewModel by viewModel()
...
}
// Inject into fragment
class MyFragment: Fragment() {
// don't confuse with by viewModels()
private val viewModel: UserViewModel by viewModel()
...
}
// Sharing viewmodel of activity between fragments
class MyFragment: Fragment() {
// don't confuse with by activityViewModels()
val activityViewModel: AuthViewModel by activityViewModel()
}