In the previous blog, we explored the foundations of design patterns and Dependency Injection (DI). Now it’s time to dive deeper into Koin—a lightweight and developer-friendly DI library for Android. This post will guide you through the core concepts of Koin, how to set it up, and build a simple "Hello Koin" example.
Koin is designed to make dependency injection in Android straightforward and intuitive. Unlike other DI frameworks like Dagger, Koin focuses on simplicity and avoids boilerplate code. Here are a few reasons why Koin stands out:
Lightweight: No code generation or proxy classes required.
Kotlin-first: Built with Kotlin DSL, making it concise and expressive.
Easy to integrate: Quick setup with minimal configuration.
Jetpack Compose ready: Seamlessly integrates with modern Android libraries.
Follow these steps to integrate Koin into your Android project:
Add the required Koin dependencies to your build.gradle
file:
implementation "io.insert-koin:koin-android:3.x.x"
implementation "io.insert-koin:koin-androidx-compose:3.x.x" // For Jetpack Compose support
Create an Application
class and initialize Koin in the onCreate
method:
import android.app.Application
import org.koin.core.context.startKoin
import org.koin.dsl.module
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// Start Koin
startKoin {
modules(appModule)
}
}
}
Declare the Application
class in your AndroidManifest.xml
file:
<application
android:name=".MyApplication"
...>
</application>
A module in Koin is a container for defining how dependencies should be created and provided. Here’s an example:
import org.koin.dsl.module
val appModule = module {
// Define a single instance of ApiService
single { ApiService() }
// Define a single instance of UserRepository, which depends on ApiService
single { UserRepository(get()) }
}
Koin supports constructor injection, making it easy to use dependencies in your classes. For example:
class LoginViewModel(private val userRepository: UserRepository) {
fun loginUser() = userRepository.getUserData()
}
To inject dependencies into Android components like activities or view models, use the by inject()
or viewModel()
delegate:
import org.koin.androidx.viewmodel.ext.android.viewModel
class LoginActivity : AppCompatActivity() {
private val loginViewModel: LoginViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
// Use the viewModel
loginViewModel.loginUser()
}
Let’s build a minimal example to understand Koin in action.
class ApiService {
fun fetchMessage(): String = "Hello from ApiService"
}
class HelloRepository(private val apiService: ApiService) {
fun getMessage(): String = apiService.fetchMessage()
}
val helloModule = module {
single { ApiService() }
single { HelloRepository(get()) }
}
class HelloApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
modules(helloModule)
}
}
}
class HelloActivity : AppCompatActivity() {
private val helloRepository: HelloRepository by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_hello)
// Fetch and display message
val message = helloRepository.getMessage()
findViewById<TextView>(R.id.textView).text = message
}
}
When you run the app, the TextView
will display: Hello from ApiService
.
With the basics of Koin in place, you’re ready to explore advanced features such as:
Using Koin in Jetpack Compose.
Scoping dependencies for specific features or lifecycles.
Testing with Koin’s built-in test utilities.
In the next blog, we’ll dive into how to use Koin with Jetpack Compose to build modern and reactive Android UIs.
Akshay Nandwana
Founder AndroidEngineers
You can connect with me on:
Join our upcoming classes
https://www.androidengineers.in/courses