Image by rawpixel.com on Freepik
In this blog, we are going to learn about Koin, a new dependency injection framework for Android Developers.
What is Koin?
Dependency injection is a pattern that shows how the dependencies should be provided to fulfill the IOC(Inversion of Control) principle which says:
“A class that is using dependency should not create it.”
The most commonly used approach to implementing that pattern is to provide a dependency through the constructor of a class.
Koin is a DI framework for Kotlin developers, completely written in Kotin. It is very light weighted. It supports the Kotlin DSL feature. It is one of the easy DI frameworks which doesn’t require a steep learning curve to get hold of it.
Why is it important to follow the principle?
It is important because when we follow the IOC principle, it facilitates us to easily substitute all the dependencies with mocks in unit tests and easily test only one class at a time.
For instance, if you want to have a lot of ViewModels, then you will probably get hundreds or even thousands of lines in ViewModelsModules class. This problem will also occur time to time while working on large enterprise projects like OTT apps or E-commerce. Fortunately, Koin supports us to load modules dynamically. So, this might be a best solution.
Understanding terminologies in Koin:
While working with Koin, there are a few terminologies we need to understand-
- module – it creates a module in Koin that would be used to provide all the dependencies.
- 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 every time it is injected.
- get() – it is used in the constructor of a class to provide the required dependency.
How do Dagger, Hilt, and Koin differ?
In comparison to Dagger or Hilt, Koin has a different approach to managing dependencies. To provide any dependency we don’t use any annotation since koin does not generate any code at all. We have to provide modules with factories that will be used to create instances of each class that will be needed in our project.
Dagger needs to use an annotation processor to scan the code and generate appropriate classes. It may also take some time and it may slow down our build. On the other hand, because Koin resolves dependencies at runtime it has slightly worse runtime performance.
As per the Google search statistical observations shown above, it is very clear Koin gains more reach over Dagger2.
Before we move further, you should create an empty activity project and give it a name of your choice. Wait for the project build to complete then add the following dependency on your app-level build.gradle file.
Creating project components:
We are going to need some components that depend on each other for demonstration. Let’s create a scenario. Create a Kotlin file and add the following code into that-
The first class is a Student class, a student has a course of study and a friend to play with. Therefore, the Student class depends on those classes.
It needs them to call or access the study() and play() functions contained in the Course and Friend classes respectively. To solve this dependency we add the two classes as parameters.
This means that the Student class can not be instantiated without instances of Course and Friend classes. Open the MainActivity file and replace the onCreate function with the following code.
The application uses View binding to access the default TextView with an id of text_view. To learn more about View binding- Visit this link.
The code creates instances of all the classes. Upon running the application, the following text view will display:
There is nothing wrong with the application as it is. But, as we mentioned earlier, depending on this kind of dependency injection will make the application hard to maintain as it scales. Let’s see how Koin can help us manage these dependencies.
Creating a Koin module:
Koin uses modules to create dependencies. Create a new Kotlin file with the name ‘module’ and add the following code.
As the name suggests, The module function is used to create a module.
- Single is used to create a singleton instance. This means that Koin will return the same instance of the class when the dependency is needed. We have made the Course a singleton since we assume that all the students do the same course.
- Factory, on the other hand, is used when we want a new instance of the class every time we call it.
- The get function is used to get the required dependency only if it has been specified in the module.
- It detects the type of dependency we need and fetches it for us. That’s all we need for the module.
Starting Koin is fairly simple. Create an application class with the name of your choice and add the following code to start Koin.
We use the startKoin function to start Koin. And that’s it! Koin is fully set up. Now, let’s use Koin in our MainActivity. Replace the onCreate method of the MainActivity with this.
The reduction of lines of code is noticeable. By inject delegate is used to lazily inject dependencies. We can also use the get function to get the dependency non-lazily.
In this article, i have given an understanding of dependency injection and how to manage dependencies using a Kotlin dependency injection known as Koin. We have seen how Koin is easy to set up and work with. We have also seen how dependency injection helps us in making our applications manageable.
I hope the tutorial gives you the insights you need to start using this great framework. For any queries, you can contact us here.