Dependency Injection with Koin on Android.

Daniel
The Startup
Published in
6 min readApr 13, 2020
Dependency Injection

Koin can bring easy dependency injection to android, standalone or web application projects. This tutorial will show how to use Koin on your Android project.

If you just want to download the code and check it by yourself, the repository is : https://github.com/lluzalves/KoinApp

But what is dependency injection anyways?

An application can be composed of many objects that will eventually have to collaborate to perform tasks. When this happens, we call it a dependency.

Because of its dependencies, a class will have to obtain references to the required dependents objects and that will make it committed to a particular set of objects. Most of the time these required dependencies are passed through the constructor.

When an application becomes more complex and grows in size it might have issues related to code reusability and an increasing need to apply refactor. To handle this kind of issue, we can make use of the dependency injection technique, by diverging usage and creation of dependencies.

Let’s add Koin to our project!

To add Koin to the project, open the build.gradle file and add the following Koin dependency and sync :

implementation "org.koin:koin-android:2.0.1"
testImplementation "org.koin:koin-test:2.0.1"
testImplementation "com.nhaarman:mockito-kotlin:1.5.0"

If the application is modularized, change implementation to api so you can access Koin it in other modules, if required.

Let’s write our first Koin module!

Now, create a Kotlin file named ApplicationModules , it will contain the dependencies we want to inject.

A Koinmodule is a space to declare components. It allows you to provide a collection of objects that will persist with the entire context lifetime that it belongs to.

To define a module use the module block and declare the dependencies inside of it:

ApplicationModule.kt

Now let’s initialize Koin!

In case the project don’t have a custom Application class, you will need to create one and declare it in your manifest file.

Your custom App class should override OnCreate() method and call startKoin(), it is responsible to return a KoinApplication instance that represents a Koin Container configuration with all the modules and definitions that was declared in startKoin(). Attention, startKoin() should only be called once.

androidLogger() is used to set the Koin log level.

androidContext() can be used to set the application Context to the Koin Container but also to inject it when necessary.

modules() is used to set the modules that we have declared to be attached to the container.

To finish this process open the Manifest , and set the value of the property android:name to your custom App class.

Injection time!

For Koin we can have 3 types of scope. We can define it as:

single, which is a singleton, this type of scope will persist for the entire application lifetime.

factory, for this type, Koin will provide a new object for each time we require an instance.

scoped, in this case, Koinwill provides an object that will persist as long the associated scope lifetime exists.

In this tutorial, we will only talk about single and factory .

Use case as single.

The most common ways to resolve dependencies with Koin is by: implementing the KoinComponent interface or providing the required dependency through constructor injection.

Implementing the KoinComponent interface is faster, it gives the class access to Koin features like get() and inject() but we can solve this with a better approach by using constructor injection .

The constructor injection approach makes the process simpler, because the class will only care about the dependencies it needs and not about who will satisfy them.

It offers a more robust way to have consistent state, as soon as the class is constructed and not only when the field injection is completed and it makes testing easier because we are declaring the dependencies in the constructor.

Approach 1 - Constructor injection.

Let’s say your application needs to store and provide data using SharedPreferences, this class should be able to provide a way to put and retrieve data from a SharedPreferences and it will also have a Context dependency.

When we started Koin , the Context was injected and now can be retrieved by calling androidContext() .

We are going to declare a single, and pass the Contextto the object constructor, that way Koin can provide the AppPreferences dependency that we want to use.

In our Activity, Fragment or Service classes, it is easy to retrieve declared instances from Koin modules. Theses classes have access to Koin features like:

by inject() — lazy injected

get() — eager injected

release() — release module’s instance

getProperty() / setProperty() — get/set property

In this case, we will make use of by inject() , to lazy inject the AppPreferences.

Now it is possible to inject the AppPreferences instance and use it to put or retrieve data from SharedPreferences.

Approach 2 - Implementing the KoinComponent.

If AppPreferences implements the KoinComponent , it gives the class access to the same Koin features that we have in the MainActivity, so it is possible to use by inject() to inject the Context lazily in AppPreferences.

Use case as factory.

While single provides a unique instance during the entire application lifecycle, factory will provide a new instance of the requested dependency every time it needs to be injected.

Let’s improve our previous example by applying the MVP design pattern to make use of factory .

Now that things are more clear, the Presenter will be responsible to return the profile name and should notify the View when everything is completed, the MainActivity that implements the View will be responsible to show the data and it will have the presenter lazily injected by Koin.

To declare the presenter dependency, we will use factory. As long as a MainContract.MainView is given, the factory will return a new MainPresenter instance. Add the following code to applicationModule file :

MainView needs to be provided so Koincan be able to inject the presenter in the MainActivity, to do this use paramentersOf() expression available in Koin , it allows to indicate input arguments for the object constructor and it will pass the required view to the presenter factory.

Let’s Test.

Let’s see if the presenter is behaving as expected. The test class should implement KoinTest interface, so we can do our injections properly. Koin needs to be started before we run the tests.

By using Mockito.verify() we are checking if after calling presenter.onComplete() any interaction happened to our view mock, specifically the showData() method.

Now just run the test and see the result. That’s it for now. Thanks for reading. :)

--

--