avatarYanneck Reiß

Summary

The article discusses the use of Koin 3.2 and Koin Annotations for dependency injection in Android apps.

Abstract

The article introduces Koin 3.2 and its new feature, Koin Annotations, for dependency injection in Android apps. Koin Annotations uses the Kotlin Symbol Processing API to provide a compiler plugin that allows for the declaration of injectable classes via annotations. The article provides an example of how to declare dependencies using modules and Koin Annotations, as well as how to start Koin. The author concludes that Koin provides an easy-to-use API for integrating dependency injection into Android apps, and encourages readers to give it a try.

Opinions

  • The author believes that Koin provides a very easy-to-use API for integrating dependency injection into Android apps.
  • The author suggests that Koin can be a relief for those who are still stuck using complex DI frameworks.
  • The author encourages readers to try out Koin and check out the official documentation for more information.

Easy Dependency Injection With Koin 3.2 And Koin Annotations

Dependency Injection for Android Apps has never been simpler

Photo by Alexandre P. Junior on Pexels

The Koin dependency injection (DI) framework has already a reduced complexity in comparison to other options like Dagger.

However, using the latest Koin version 3.2, we now can make use of a few new functionalities that reduce the complexity of integrating DI into our Android app even more.

One of the new features are Koin Annotations plugin. It uses the KSP (Kotlin Symbol Processing API) to provide a compiler plugin that allows us to declare our injectable classes via annotations. That means that, for simple cases, while we still have the capability to do so, we no longer are enforced to declare additional modules and just need to add a simple annotation above the classes we want to inject.

While Koin Annotations are at the time of writing still in beta, in this article, we will take an early look at how we can declare dependencies with Koin using the usual approach with the new functionalities of Koin 3.2 and also how we can migrate to dependency declarations using Koin Annotations.

1. Declaring Koin Modules (the usual way)

Before we start diving into the new feature, let’s take a step back and see how we usually declare injectable classes with Koin.

To make it easier, we use a hypothetical example that also considers Android’s recommended way of separation of concerns into UI (our ViewModel) domain (our use case) and data layer (our repository).

Let’s assume we have a class ExampleUseCase that we want to inject into our ExampleViewModel. The ExampleUseCase makes use of functions of an ExampleRepository class.

1.1 Setup

Before we can use Koin, we need to add the respective dependency. Therefore make sure that you have the following dependency in your app-level build.gradle file:

1.2 The repository

We first declare the ExampleRepository in the following way:

To declare the repository as injectable, we create a new module repositoryModule and declare it via factoryOf keyword. Therefore everytime we inject the ExampleRepository a fresh instance will get created.

If you have a use case where you only want to create a single instance of your class that is used across the app’s lifecycle, could can also make use the singleOf keyword which creates a singleton instance that will be kept inside the Koin container.

1.3 The UseCase

Our ExampleUseCase takes the ExampleRepository as constructor parameter.

The declaration for the respective useCaseModule looks just like the previous one for the repository.

1.4 The ViewModel

Last but not least we have our ExampleViewModel that requires our ExampleUseCase as constructor parameter.

To use constructor injection with our ExampleViewModel, we need to declare it in a module using the viewModelOf keyword.

By using that keyword we declare a factory instance of the respective ViewModel class. The created instance will be handled by an internal ViewModelFactory and also reattach the respective ViewModelViewModel if required.

The viewModelModule therefore could look like the following:

Note: If you do not constructor injection in your ViewModel, you could skip the module declaration step and just let the ExampleViewModel implment the KoinComponent interface. By doing so you enable it to use the inject keyword that directly let’s you a dependency into a variable.

To inject a ViewModel dependency with Koin, we no longer use the by viewModels delegate but the by viewModel one like the following example shows:

1.5 Starting Koin

Now that we declared our dependencies, and talked about how we can inject the ViewModel dependency into our Activity / Fragment, as the last step, we need to makesure that Koin gets initialized.

If you just want to scope the modules to the application scope, you can just implement a custom Application class in initialize Koin in the onCreate function like the following code shows for our snippet.

Even if we are not using this feature in our example, I found it worth mentioning that by declaring the androidContext(..) you can also inject the application context into your classes.

As you can see we use Kotlin DSL to declare inside the startKoin body our modules using the modules keyword. The Module class overloads the '+' operator. That’s why we can just concatenate our modules using that operator.

2. Using Koin Annotations

So now that we saw how we can declare our injectable dependencies using the modules approach, let’s go further and consider the same using the new Koin Annotations feature.

2.1 Setup

As a first step we need to extend our Koin related dependencies in our app-level build.gradle like you can see in the following code-snippet:

Next, we need to introduce KSP into our project by adding the following to the top of the same file:

At the time of writing the current KSP version is 1.6.21–1.0.5 where the first part of that version tag describes the Kotlin version you are using in your project. If you have another version in use, you can check the GitHub releases page for a matching version.

2.2 Declaring our dependencies using annotations

As the name of the Kotlin Annotation feature already implies, we now no longer need to go the extra step to declare our dependencies in a separate module but can do it just by adding an annotation to each of our classes.

The previously discussed singleOf keywords as annotation maps to an @Single while the factoryOf can be replaced by annotating the respective classes with the @Factory annotation.

Also the viewModelOf declaration can be replaced via @KoinViewModel annotation.

In the following code snippet you can see the migrated classes with their respective required annotations at a glance:

2.3 Starting Koin

The only thing now that we need to adapt is the Koin initialization. Because we no longer have separated modules. Using Koin Annotations, by default a defaultModule gets generated that holds all our dependencies.

We therefore only need to add this defaultModule into the modules(..) function and are good to go.

3. Conclusion

In this article we took a look at the latest version 3.2 of the Koin dependency injection framework. We saw how we can declare dependencies using modules and also by using the new Koin Annotations feature.

In my opinion Koin just does it right. It provides a very easy to use API to implement integrate dependency injection into our Android app’s that makes testing at the end very comfortable.

Howev, while the API is easy to use, it also has a broad variety of features that we didn’t even mention in this article. If you like to know more about it, make sure to check out the official documentation.

As a last point, in case you have not done so yet, I can only motivate you to give Koin a try. It can be a real relief if you are still stuck to other complex DI frameworks.

I hope you had some takeaways, clap if you liked my article, make sure to subscribe to get notified via e-mail, and follow for more!

Android
Android App Development
Dependency Injection
Koin
Programming
Recommended from ReadMedium