Easy Dependency Injection in Android with Koin

Viktor Petrovski

Viktor Petrovski

Senior Android Developer

Many developers are moving from Dagger to Koin . But can this framework simplify your Android development? Let's find out!

Before we move forward in talking about Koin and it's advantages lets make sure we all know what Dependency Injection is and it's usefulness.

In programming terms, when class A uses some functionality of class B, then we say that class A has a dependency on class B. Transferring the task of creating the object to someone else and directly using the dependency is called dependency injection.

With S.O.L.I.D principles and Clean Architecture taking a big part of modern software development, there's a tight connection between dependency injection and the Inversion of control principle. According to the principle:

A class should concentrate on fulfilling its responsibilities and not on creating objects that it requires to fulfill those responsibilities. And that’s where dependency injection comes into play: it provides the class with the required objects.

Before Kotlin came, Dagger was, for quite some time, the de-facto standard for DI in the Android world. Supported by Google, it uses annotations and compile-time code generation to create your dependency graph and provide dependencies. No blame here, I was also using it for quite some time, but as it happens, it’s a framework developed in Java world. On the other side, Koin is built using the functional programming nature of Kotlin, using only functional programming so we can say goodbye to code generation, reflection and long compile time.

Koin Android

The Simplicity of Koin 

If you ever used Dagger 2, I'm pretty sure you already hate the Thermosiphon example. Even after reading it a few times, you are still insecure about how to start working with it. Well, integrating Koin is quite easy.

Add Koin to your gradle file

implementation "org.koin:koin-android:${versions.koin}"

implementation "org.koin:koin-android-architecture:${versions.koin}"

testImplementation "org.koin:koin-test:${versions.koin}"

Create your module and declare factory for it

class Controller(){

val myModule = module {
// declare factory instance for Controller
factory { Controller() }
}
}

Start Koin inside your Application class 


class MyApp : Application() {
override fun onCreate() {
super.onCreate()
startKoin(this, listOf(myModule))
}
}

Now you can already start using the instance of Controller class inside your Activities.

// Just inject in a simple Activity 
class MyActivity() : AppCompatActivity() {

// lazy inject Controller into property
val service : Controller by inject()

}

Easy and painless right ? No need for extra components, providers and interfaces... Welcome to Koin!

If you are worried about injecting your ViewModels, Koin has your back. It supports natively injecting ViewModels and it is really easy too!

// Injected by constructor 
class MyViewModel(val repo : MyRepository) : ViewModel()

// declared ViewModel using the viewModel keyword
val myModule : Module = module {
viewModel { MyViewModel(get()) }
single { MyRepository() }
}

// Just get it
class MyActivity() : AppCompatActivity() {

// lazy inject MyViewModel
val vm : MyViewModel by viewModel()
}

Let's Look at Some of the Flaws the Framework Has

In the following example, we do have the AccountRepository class which in order to work it needs the RemoteRepository to authenticate the user and LocalRepository to save it locally afterwards.

class AccountRepository constructor( 
private val remoteRepository: RemoteRepository,
private val localRepository: LocalRepository )

The Koin module will look something like this:

val networkModule = module {    
  single { 
   RemoteRepositoryImpl(BASE_URL) as RemoteRepository 
  }
 
  single { 
   LocalRepositoryImpl(androidContext()) as LocalRepository  
  }

  factory { AccountRepository(get(), get()) }
}

While Koin already knows how to create the required objects for AccountRepository, we will need to add a little more boilerplate and explicitly declare the get() keyword in order to make everything work.

The next drawback is that there’s no dependency injection error at compile time. In Dagger, it will tell you that you forgot to provide an instance if it can’t satisfy the injection. In Koin, you only know the problem during runtime.

This is potentially a huge big no, but not to worry much. Koin provides a way where you can run the test to make sure all components are satisfied correctly. You can find out more about this in their Documentation. Just make sure you write your tests properly and don't publish any apps before checking all the Modules.

Adopting a new framework where there isn't a big community yet can be challenging! I've noticed that some of the error logs you will get are not too descriptive. I would suggest being careful while configuring your modules because copy-pasting the error on StackOverflow may not solve your problem.


Learning Process

The best approach for adopting new skill, technology or even a framework is by doing it. Get your hands dirty and start working on a side project that you will have the liberty to experiment with Koin. Create scenarios you've had difficulties in the past and try to ease them using this framework. Before starting with any DI framework, I would strongly recommend learning about Dependency Injection in general, why it is useful and how it can help us in writing tests.

Koin is pretty new and there aren't tons of materials like there is for Dagger 2, but don't take this as a huge roadblock. The simplicity of Koin is what attracted me the most. You can start off by going through their official documentation, which is also another great place to improve your Android skills. You can do this through video tutorials on Caster IO where they have a brand new course on Koin that will help you learn a lot of cool features about it.

Koin Android

Koin is super easy to get started with and has a clean and easy to understand documentation. Just add a couple of lines of code and you are ready to start! It is super useful if you are working on a new side project and don't want to bother spending hours configuring Dagger 2 and its components. With Koin, you can start creating your objects in a few lines of code. How awesome is that?

Conclusion

Technology is thriving at a really high pace, new frameworks and tools are coming out daily and it's not getting easier for us to keep track of everything. Get comfortable in one set of tools you use daily, but don't be afraid to try out new things. Don't wait for a framework to be super famous for you to start using it, experiment and try out new things. Create your favorite technology stack on your own, don't use someone else's template. What works best for him doesn't mean it will for you too.

Like everything in life, there’s always Ying and Yang. Whether Koin fits your project is up to you to decide. I've just launched my first app that is fully integrated with Koin and excited to see the feedback. I’ll be sticking to Koin for a while and see how well it can perform on higher scale apps.

Please leave your thoughts, if you have experimented around with it.