終於只剩三篇就結束了,今天讓我們來談談 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 怎麼在一個獨立的 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 可以使用,不過今天限於篇幅,就只在這邊點到為止囉,有興趣的朋友歡迎自行玩玩看!