Koin

The Koin library allows you to implement dependency injection (DI) scenarios in a Kotlin application.

Steps to use Koin:

  1. define interface of some service
  2. define implementation of that service
  3. add implementation of service to the koin module
  4. start koin with specified modules
  5. 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.

Koin on github .

gradle dependencies

Code example
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

Start koin example example
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.

Code example
// 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()
}

koin modules example

koin modules example