Blog Infos
Author
Published
Topics
Published
Topics

This is the second article in an article series that will discuss the dependency injection and service locator patterns, explain how they differ, and detail the most prominent Multiplatform Mobile libraries and approaches to implementing these patterns. This article introduces the first library: Koin. You can find the first article in the series here.

Koin is a well-known open-source Service Locator dependency management library that has support for Android, Ktor, and Multiplatform.

A Little Boilerplate
data class StaffMember(val name: String, val position: String)
interface StaffLister {
fun findAllStaffMembers(): List<StaffMember>
}
class StaffListerImpl : StaffLister {
override fun findAllStaffMembers(): List<StaffMember> {
return listOf(
StaffMember(
"Pamela Hill",
"Developer Advocate"
)
)
}
}
class SearchBox(private val lister: StaffLister){
fun findStaffMemberByName(name: String): StaffMember? {
return lister.findAllStaffMembers().firstOrNull {
name == it.name
}
}
}
view raw Boilerplate hosted with ❤ by GitHub
Initialization

To initialize Koin, it is necessary to call the startKoin function with one or more modules of dependency bindings within the context of the application. The code below contains the definition of the application module and an initKoin function. The initKoin function then needs to be called during the right parts of the application lifecycle initialization.

view raw SearchBox hosted with ❤ by GitHub

commonMain/…/SearchBox.kt

 

Android
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
initKoin()
}
}
view raw MyApplication hosted with ❤ by GitHub

androidApp/…/MyApplication.kt

 

iOS

Note that we are using a bridge from the iOS application to the iOS shared code to the initKoin function, which is unnecessary in the Android application.

fun initKoinApp(){
initKoin()
}
view raw Helper hosted with ❤ by GitHub

iosMain/…/Helper.kt

@main
struct iOSApp: App {
init() {
HelperKt.doInitKoinApp()
}
}
view raw iOSApp hosted with ❤ by GitHub

iosApp/…/iOSApp.swift

 

Usage

In order to hook the user interface up to the search box implementation, it is necessary to inject the SearchBox into a user interface component. This is fairly straightforward for Android, but on iOS, we once again have to use a bridge from the iOS application to the iOS shared code, where the SearchBox is injected (notice also that the “bridge” is a KoinComponent).

Android
import org.koin.android.ext.android.inject
...
class MainActivity : AppCompatActivity() {
private val searchBox: SearchBox by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val tv: TextView = findViewById(R.id.text_view)
tv.text = searchBox
.findStaffMemberByName("Pamela Hill").toString()
}
}
view raw MainActivity hosted with ❤ by GitHub

androidApp/…/MainActivity.kt

Job Offers

Job Offers


    Senior Android Software Engineer (f/m/d)

    Paradox Cat GmbH
    Munich
    • Full Time
    apply now

    Kotlin Multiplatform Mobile Developer

    Touchlab
    Remote
    • Full Time
    apply now

    Android Software Engineer (f/m/d)

    Paradox Cat GmbH
    Munich
    • Full Time
    apply now
Load more listings

OUR VIDEO RECOMMENDATION

,

Diving into Koin 3.2 & Koin Annotations 1.0

​​Koin is the Kotlin dependency injection framework well known for its ease of use and efficiency. It has been greatly appreciated by the Android community since 2017. In 2022, a new major version of the…
Watch Video

Diving into Koin 3.2 & Koin Annotations 1.0

ARNAUD GIULIANI
Koin Project Lead

Diving into Koin 3.2 & Koin Annotations 1.0

ARNAUD GIULIANI
Koin Project Lead

Diving into Koin 3.2 & Koin Annotations 1.0

ARNAUD GIULIANI
Koin Project Lead

Jobs

iOS
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
...
class SearchBoxHelper : KoinComponent {
private val searchBox : SearchBox by inject()
fun findByName(name: String) : String =
searchBox.findStaffMemberByName(name).toString()
}
view raw SearchBoxHelper hosted with ❤ by GitHub

iosMain/…/SearchBoxHelper.kt

struct ContentView: View {
let staff = SearchBoxHelper().findByName(name: "Pamela Hill")
var body: some View {
Text(staff)
}
}
view raw ContentView hosted with ❤ by GitHub

iosApp/…/ContentView.swift

 

Opinion

Koin is a lovely dependency management library for multiplatform development. I have developed a large-scale Android app with it, after finding that Dagger was too complicated for the team to understand (this was before Hilt). The team behind it is passionate and takes even harsh criticism from the community in their stride, taking it as constructive and using it to make the library even better. I have two examples of this:

Criticism 1: Since there is no compile-time check as with Dagger, it can lead to crashes when a needed dependency is omitted

While there is no way to make Koin a code-generating DI library, they took this criticism and introduced a way to check your module dependency graph during your unit testing cycle. This clever move allows you to make checking your modules part of your CI/CD pipelines and your app won’t hit production with such a blaring unit test failure, assuming you remember to add all your modules.

class CheckModulesTest : KoinTest {
@Test
fun verifyKoinApp() {
koinApplication {
modules(module1, module2)
checkModules()
}
}
}

Criticism 2: All the calls to get() for long dependency lists quickly gets out of hand

In the versions of Koin before 3.2, long dependency lists meant long argument lists of get() arguments being passed mindlessly to constructors. But in version 3.2, a new constructor DSL was introduced that eliminated this problem. For example:

module {
factory { StaffListerImpl() as StaffLister }
factory { SearchBox (get()) }
}
view raw module1 hosted with ❤ by GitHub

became instead:

module {
factoryOf(::StaffListerImpl) bind StaffLister::class
factoryOf(::SearchBox)
}
view raw module2 hosted with ❤ by GitHub

Now, imagine the benefit if SearchBox had several dependencies!

The remainder of this series will focus on the actual libraries and approaches for dependency management in Multiplatform Mobile, and will feature articles on:

  • Kodein
  • Kotlin-Inject
  • Manual injection

Stay tuned!

This article was originally published on proandroiddev.com on August 31, 2022

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
I develop a small multi-platform(android, desktop) project for finding cars at an auction using…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu