Dependency Injection with Koin and Kotlin in Android

There are a lot of reasons to use Dependency Injection, or even a Framework for it.

In this Article you’ll learn what Dependency Injection is, what benefits and downsides it has and how to use it with the usage of the Koin Framework.

Let’s look at a example of a House with a Doorbell to better understand what dependency injection is.

The House class has a function that returns a String representing the current Ringtone according to the installed doorbell.

Without Dependency Injection:

class House() {
    private val myDoorbell: Doorbell
   
   init {
       myDoorbell = SpeakingDoorbell()
   }
   
   fun ringDoorbell(): String {
       return "Current ringtone " + myDoorbell.getRingtone()
   }
}

fun main() {
    val myHouse = House()
   
    println(myHouse.ringDoorbell())
}

With Dependency Injection:

class House(private val myDoorbell: Doorbell) {
   fun ringDoorbell(): String {
       return "Current ringtone " + myDoorbell.getRingtone()
   }
}

fun main() {
    val myDoorbell: Doorbell = SpeakingDoorbell()
    val myHouse = House(myDoorbell)
   
    println(myHouse.ringDoorbell())
}

As you can see in the variant without Dependency Injection the House class has a direct dependency to the SpeakingDoorbell class.

With Dependency Injection this reference no longer exists. The only reference
remaining is to the generalized Doorbell Interface.

Benefits of Dependency Injection

Flexibility

Lets suppose another class FunnyDoorbell should be used in the future, which also implements the Doorbell interface.

Exchanging the SpeakingDoorbell class later on is less work with Dependency Injection.

In the first example the House class would have to change its implementation to switch to the FunnyDoorbell class.

But with Dependency Injection this change can be done without touching the House class.

In fact the House class does not even know whether it got an instance of SpeakingDoorbell or FunnyDoorbell.

This allows to write more flexible code which can be modified and extended easier.

A looser coupling between classes is achieved.

Testability

When writing tests one cannot test the House class in the first example in isolation to the SpeakingDoorbell class.

With Dependency Injection it’s very easy to insert mocks instead of the real instance.

Downsides of Dependency Injection

There is one part that got more complex though. The main function now knows not only the House class, but also the SpeakingDoorbell class.

This ultimatley leads to a really big main function, that knows almost every component.

In this small example this is no issue, but when developing large applications we want the benefits of Dependency Injection, but as few downsides as possible.

This is exactly where Dependency Injection Frameworks comes into play!

They help to structure the whole block how and when to instantiate which classes and usually bring with them a bunch of useful features.

So let us look into the Dependency Injection Framework Koin.

Setting up Koin

Gradle

Add the following to your gradle configuration.
Get the latest Koin version [here](https://insert-koin.io/docs/setup/v3).

// Add Maven Central to your repositories if needed
repositories {
    mavenCentral()    
}
dependencies {
    // Koin for Android
    implementation "io.insert-koin:koin-android:$koin_version"
}

Application

Create an application class if you have none yet (don’t forget to add it to the manifest).

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
     
        startKoin {
            androidContext(this@MyApplication)
            modules(
                module {
                    single { House(get()) }
                    single<Doorbell> { SpeakingDoorbell() }
                }
            )
        }
    } 
}

Profit

That’s it! This is the basic Koin setup. As you can see the House class now even fetches its needed instance of Doorbell.
Simply call startKoin, configure the AndroidContext and define some Beans. These can also be injected like this into Android components like activities:

val myVariable: MyVariableType by inject()

ViewModel injection

The avid reader might already have noticed something. “What about our ViewModels. They have a lifecycle and should not get created just like that”.

To fix this issue there exists an extension for Koin.

Instead of declaring a Bean like that

single { MyClass() }

we use

viewModel<MyViewModelType> { MyViewModel() }

The injection is then done inside the fragment like that:

val myViewModel: MyViewModelType by viewModel()

Conclusion

Using Dependency Injection, especially with a framework, can be intimidating for a new programmer.

But in the most cases the positive aspects outweigh the negatives and the complexity of setting up a dependency
injection framework is quite low.

There are a lot of other things Koin can do like defining factories instead of singles, directly helping out with tests, instantiating fragments, or much more.

Have a glance at the official documentation

Developer Toolbelt – private edition

Inspired by the Blog Post https://gingter.org/2016/12/15/my-developers-toolbelt-2016 I want to share what my tool set looks like in 2022:

  • PyCharm as main IDE for Python and markdown
  • pandoc for converting markdown to PDF
  • Android Studio
  • Github (now with private repo support)
  • Guitar Pro Version 7.5 (Thomann Affiliate Link)
  • Logic Pro X
  • Spotify for getting into “the Zone” – Currently Hooray! Hooray!
  • Tomato Timer for doing Pomodoro
  • Firefox with iMacros / Greasemonkey for browser automation / optimization
  • yED for diagrams
  • Google Spreadsheet for Content Calendar & and book writing process

I really love PyCharm and it gets better with every update. It’s currently my Swiss army knife. I even use it for managing github repos which don’t involve code 🙂

Pipenv Easter Egg

I’ve found this little easter egg hidden in pipenv:

if not environments.PIPENV_HIDE_EMOJIS:
    now = time.localtime()
    # Halloween easter-egg.
    if ((now.tm_mon == 10) and (now.tm_mday == 30)) or (
        (now.tm_mon == 10) and (now.tm_mday == 31)
    ):
        INSTALL_LABEL = "🎃   "
    # Christmas easter-egg.
    elif ((now.tm_mon == 12) and (now.tm_mday == 24)) or (
        (now.tm_mon == 12) and (now.tm_mday == 25)
    ):
        INSTALL_LABEL = "🎅   "

https://github.com/pypa/pipenv/blob/main/pipenv/core.py

2021 – Advent of code – Day 3

Part 1

You need to use the binary numbers in the diagnostic report to generate two new binary numbers (called the gamma rate and
the epsilon rate). The power consumption can then be found by multiplying the gamma rate by the epsilon rate.

Each bit in the gamma rate can be determined by finding the most common bit in the corresponding position of all numbers
in the diagnostic report. For example, given the following diagnostic report:

00100
11110
10110
10111
10101
01111
00111
11100
10000
11001
00010
01010


Considering only the first bit of each number, there are five 0 bits and seven 1 bits. Since the most common bit is 1, the first bit of the gamma rate is 1.

The most common second bit of the numbers in the diagnostic report is 0, so the second bit of the gamma rate is 0.

The most common value of the third, fourth, and fifth bits are 1, 1, and 0, respectively, and so the final three bits of the gamma rate are 110.

So, the gamma rate is the binary number 10110, or 22 in decimal.

The epsilon rate is calculated in a similar way; rather than use the most common bit, the least common bit from each position is used.
So, the epsilon rate is 01001, or 9 in decimal. Multiplying the gamma rate (22) by the epsilon rate (9) produces the power consumption, 198.

Use the binary numbers in your diagnostic report to calculate the gamma rate and epsilon rate, then multiply them together. What is the power consumption of the submarine? (Be sure to represent your answer in decimal, not binary.)

Reading the data

import pandas as pd

df = pd.read_csv("./aoc_day_03_test_data.txt", dtype = str, header=None)
df.columns = ["original"]

Continue reading “2021 – Advent of code – Day 3”

2021 – Advent of code – Day 2

Part 1

Today the puzzle got a bit trickier than Day 1.

The submarine seems to already have a planned course (your puzzle input). You should probably figure out where it's going. For example:

    forward 5
    down 5
    forward 8
    up 3
    down 8
    forward 2

Your horizontal position and depth both start at 0. The steps above would then modify them as follows:

    forward 5 adds 5 to your horizontal position, a total of 5.
    down 5 adds 5 to your depth, resulting in a value of 5.
    forward 8 adds 8 to your horizontal position, a total of 13.
    up 3 decreases your depth by 3, resulting in a value of 2.
    down 8 adds 8 to your depth, resulting in a value of 10.
    forward 2 adds 2 to your horizontal position, a total of 15.

After following these instructions, you would have a horizontal position of 15 and a depth of 10. (Multiplying these together produces 150.)

Calculate the horizontal position and depth you would have after following the planned course. What do you get if you multiply your final horizontal position by your final depth?

So Pandas here we go again: Continue reading “2021 – Advent of code – Day 2”

10 tips for creating co-ownership in a code base

When you learn a new language or a framework you almost always certainly start fresh with a new clean project aka green field project.

In the industry you rarely get the chance to do so. You will have to start with code which has already been there for a specific time. These projects are called brown field. And brown not in a good sense. Brown can mean mud to sh… Continue reading “10 tips for creating co-ownership in a code base”

How to fix android.view.InflateException: Error inflating class fragment

I got the error

E/AndroidRuntime: FATAL EXCEPTION: main
Process: de.creatronix.levelup, PID: 17026
java.lang.RuntimeException: Unable to start activity ComponentInfo{de.creatronix.levelup/de.creatronix.levelup.MainActivity}: android.view.InflateException: Binary XML file line #18: Error inflating class fragment

after enabling minification in my build.

The issue is that with the usage of safeargs with custom objects we use the the @parcelize annotation which seems to be optimized away with R8 Continue reading “How to fix android.view.InflateException: Error inflating class fragment”