Kotlin Koin - Android Tutorial for Beginners

What is Koin? A pragmatic lightweight dependency injection framework for Kotlin developers Written in pure Kotlin.

What is dependency and dependency Injection? Let’s take an example. We have a relation between Car and Engine classes. To access Engine’s properties in Car class we have to create an instance of Engine Car that is simply a dependency.

instance of engine class can be created manually. but it becomes hard to instantiate the objects automatically such as in constructor.

asking someone else to create the object and directly using it is called dependency injection.

Let’s add Koin to our project!

// Koin AndroidX Scope features
    implementation "io.insert-koin:koin-androidx-scope:2.2.3"
// Koin AndroidX ViewModel features
    implementation "io.insert-koin:koin-androidx-viewmodel:2.2.3"
// Koin AndroidX Fragment features
    implementation "io.insert-koin:koin-androidx-fragment:2.2.3"
    // Koin AndroidX WorkManager
//    implementation "io.insert-koin:koin-androidx-workmanager:$koin_version"
// Koin AndroidX Jetpack Compose
//    implementation "io.insert-koin:koin-androidx-compose:$koin_version"
// Koin AndroidX Experimental features
//    implementation "io.insert-koin:koin-androidx-ext:$koin_version"}

add this koin plugin in build.gradle(app)

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'koin'
}

first create our Application class like,

class BaseApplication:Application()

add this in manifest file like,

android:name=".BaseApplication"

for Koin we have three types of Scopes , we can define it as: single, it creates a singleton that can be used across the app as a singular instance. factory, it provides a bean definition, which will create a new instance each time it is injected. scoped, it's provide an object that will persist as long the associated scope lifetime exist

Constructor injection.

class Car constructor(private val engine: Engine, private val wheel: Wheel){

    companion object{
        const val TAG ="Car"
    }
    fun getCar(){
        wheel.getWheel()
        engine.getEngine()

        Log.d(TAG, "getCar: Car is Running")
    }
}
class Engine {

    companion object{
        const val TAG ="Engine"
    }
    fun getEngine(){
        Log.d(TAG, "Engine started")
    }
}
class Wheel {

    companion object{
        const val TAG ="Wheel"
    }
    fun getWheel(){
        Log.d(TAG, "Wheel started")
    }
}

Deifne Module we keep logic in module to provide dependency like (interface and class) to provide car class Dependency create a module AppModule file.

val demoModule = module {

    single {
        Wheel()
    }

    single {
        Engine()
    }
    // every time inject new instance created if used factory scope
    // get() to inject wheel and engine dependency
    single {
        Car(get(),get())
    }
    single {
        Component()
    }
}

Implementing Koin Component To give a class the capacity to use Koin features, we need to tag it with KoinComponent interface. Let's take an example.

@KoinApiExtension
class Component() :KoinComponent{

    // lazily instantiated (when first access)
    val car: Car by inject()
    val engine:Engine by inject ()


    // also another way
    // eagerly  // when application created will be available
    val car1:Car = get()

    // val main: Main by inject()

    //val mainViewModel:MainViewModel by inject   ()

}

Now we have declared all modules (decencies). In Application class, just call startKoin{ }method that takes a lambda in which we define a list of modules

class BaseApplication:Application() {

    override fun onCreate() {
        super.onCreate()

        // first start Koin(to use)
       startKoin {
           //can keep list of modules
           modules(listOf(demoModule,))
//            modules(
//                demoModule
//            )
        }
    }
}

Let's inject in MainActivity first use @KoinApiExtension in activity,fragment etc.

@KoinApiExtension
class MainActivity : AppCompatActivity() {
    var binding:ActivityMainBinding? = null
    private val component:Component by inject()

//    private val car: Car by inject() /// not a better way create component than use

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        binding?.apply {
            setContentView(root)
            lifecycleOwner = this@MainActivity
            executePendingBindings()
        }

        component.car.getCar()
    }
}

Did you find this article valuable?

Support Sanjay Prajapat's Blog by becoming a sponsor. Any amount is appreciated!