iT邦幫忙

2022 iThome 鐵人賽

DAY 28
0
Mobile Development

Kotlin 全面啟動 系列 第 28

[Kotlin 全面啟動] Koin

  • 分享至 

  • xImage
  •  

終於只剩三篇就結束了,今天讓我們來談談 Koin 這個 dependency injection 的 framework 吧!

其實在之前的 Android 十全大補也有提過基本的介紹,今天會想要再提一次的原因是想深入討論一下 Koin 在 KMM 的使用有什麼不同,由於 KMM 切了很多層,變化就會變得更多,有沒有可能在 Android 的 UI 層我們比較想要使用 Dagger、Hilt 呢,或是對於 iOS 來說,也可能希望完全不要有 Koin 的 dependency,這時候除了開一個 function 讓 UI 呼叫 Koin 的 startKoin 之外,還有什麼更乾淨的辦法呢?

如果對 Koin 的基礎介紹有興趣的話,歡迎參考:
https://ithelp.ithome.com.tw/articles/10225818

Koin for Libraries

其實我們一開始提的問題可以簡化為 Koin 怎麼在一個獨立的 library 使用而不需要 host app 額外的呼叫 init 或其他 function,要回答這個問題,我們可以回頭看一下 Koin 所提供的 inject :

inline fun <reified T : Any> KoinComponent.inject(
    qualifier: Qualifier? = null,
    mode: LazyThreadSafetyMode = KoinPlatformTools.defaultLazyMode(),
    noinline parameters: ParametersDefinition? = null
): Lazy<T> =
    lazy(mode) { get<T>(qualifier, parameters) }

inline fun <reified T : Any> KoinComponent.get(
    qualifier: Qualifier? = null,
    noinline parameters: ParametersDefinition? = null
): T {
    return if (this is KoinScopeComponent) {
        scope.get(qualifier, parameters)
    } else getKoin().get(qualifier, parameters)
}

我們可以發現 inject 內部呼叫了 get,然後如果沒有 scope 的問題的話,它會直接呼叫 getKoin,這個原本定義在 KoinComponent 裡的 function:

interface KoinComponent {

    fun getKoin(): Koin = KoinPlatformTools.defaultContext().get()
}

getKoin 呢,則會呼叫 KoinPlatformTools.defaultContext 來得到 KoinContext

actual object KoinPlatformTools {
    actual fun defaultContext(): KoinContext = GlobalContext
}

這個 defaultContext 的實作其實是拿 GlobalContext 直接回傳,而每個 KoinContext 裡都有個 Koin 實體可以讓我們作 injection,所以其實我們只要能夠獨立建立一個 Koin 實體在 library 裡使用,就不會污染到 host app 了。

一個簡單範例如下:

internal object MyKoinContext {
    val koinApp: KoinApplication = koinApplication {
        // declare used modules
        modules(dataModule)
    }
}

// provide dependency
private val dataModule = module {
    single {
        GithubService()
    }
}

// inject dependency
private val githubService by MyKoinContext.koinApp.koin.inject<GithubService>()

我們首先建立一個 MyKoinContext,然後在裡面建立一個 KoinApplication 並把 dependency 透過 modules function 設定好,需要 dependency 時就可以透過這裡面的 koin 來得到 dependency 囉!
當然如果你願意所有 module 的 dependency 都由 Koin 處理的話,事情就會變得比較簡單了,但如果你想要隔開各個 module 之間所使用的工具,或許本文介紹的手段也是個不錯的方法,一點小小心得分享給大家,如果有其他更好的方法也歡迎留言補充!

筆者近期在看 Koin 文件的時候發現 Koin 也有支援 KSP 的 annotation 可以使用,不過今天限於篇幅,就只在這邊點到為止囉,有興趣的朋友歡迎自行玩玩看!


上一篇
[Kotlin 全面啟動] KSP III
下一篇
[Kotlin 全面啟動] Compose
系列文
Kotlin 全面啟動 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言