The pragmatic Kotlin & Kotlin Multiplatform Dependency Injection framework
实用的Kotlin和Kotlin多平台依赖注入框架
Android Studio环境为 Android Studio Flamingo | 2022.2.1
Koin的最新版本为3.4.5
Compose 最新稳定版本为1.4.3
在前面的文章中,我们介绍了在 Android 中(非 Compose)工程中如何去使用 Koin 进行依赖注入,最近正好想开发一个 Compose版 Wan Android App,在依赖注入的功能中,还是决定使用 Koin 来管理依赖注入,本篇正好介绍下 Koin 如何在 Compose 中实现依赖注入
Koin 注入普通对象
Koin 的初始化就不再多说了,第一篇文章中已经介绍的很清楚了,下面我们看下对于 Compose,Koin 需要额外添加的依赖
implementation "io.insert-koin:koin-androidx-compose:3.4.5"
在 app 的build.gradle
文件中添加上面的依赖,将 koin-compose 添加到工程中。
下面我们来看看在@Composable
方法中如何注入一个普通的对象示例
注入基本对象
// 简单的一个日志输出类
class Logger {
fun print(msg: String) {
Log.d(TAG, "Logger print: $msg")
}
}
val module = module {
// 设置它的注入类型为单例
single { Logger() }
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
// 通过 koin 的 koinInject()方法进行对象注入
val logger: Logger = koinInject()
Text(
text = "Hello $name!",
modifier = modifier.clickable { logger.print("greeting") }
)
}
# 日志输出
Logger print: greeting
从上面的代码中可以看到,module{}
在普通工程和 compose 工程中用法是一致的,只是在获取依赖对象时,compose 中需要使用 koinInject()
方法来获取,此方法也是被@Composable
修饰,并且通过remember()
来完成内部逻辑实现。
由此可以看出,在 compose 中通过 koin 实现依赖注入也是非常简单的,而且内部实现也不复杂,接下来看看如何通过限定符获取不同场景的对象示例。
绑定限定符
koin 中可以使用qualifier
来限定同一个对象不同的实例注入,下面还是通过 Logger
对象来展示下限定符的作用。
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
// 通过获取对象时,增加限定符 qualifier 参数
val logger: Logger = koinInject(qualifier = qualifier("single1"))
val logger2: Logger = koinInject(qualifier = qualifier("single2"))
Text(
text = "Hello $name!",
modifier = modifier.clickable {
logger.print("greeting")
logger2.print("greeting")
}
)
}
class Logger {
fun print(msg: String) {
// 打印的地方增加了 hashcode 值,可以方便观察对象是否为同一个
Log.d(TAG, "Logger print: $msg, ${hashCode()}")
}
}
val module = module {
// 限定符为 single1
single(qualifier = qualifier("single1")) { Logger() }
// 限定符为 single2
single(qualifier = qualifier("single2")) { Logger() }
}
在 module
中,即使两个 Logger
对象都是采用单例模式,但是它们两个的限定符值不同,此时大家想一下是否会注入两个不同的单例对象呢,一会看下日志的输出就会明白了。同时我们在获取注入的对象时,也需要加上 qualifier
参数,不然在运行之后会抛出异常,koinInject()
方法的第一个参数就是 qualifier
,这里我们传入在 module
中定义过的限定符值即可。
Logger print: greeting, 105740997
Logger print: greeting, 63142938
通过日志就可以显而易见的看出,即使通过 single{}
来管理了依赖注入,但是在限定符的作用下, 获取的时候还是会根据限定符生成不同的对象实例。
这样我们在日常开发中就可以通过限定符来管理我们想要的注入对象了。
Koin 注入 ViewModel 对象
Koin 也帮助我们在使用 ViewModel
的过程中提供了依赖注入的便捷方式,无论是有参还是无参的 ViewModel
对象,对于 Koin 来说都为我们提供了便捷的操作。
我们先定义两个 ViewModel
对象,一个无参另外一个带有 Logger
参数的构造方法
class KoinViewModel : ViewModel() {
fun print() {
Log.d(TAG, "KoinViewModel print")
}
}
class KoinParamsViewModel(
private val logger: Logger
) : ViewModel() {
fun print() {
logger.print("KoinParamsViewModel")
}
}
然后在 moudle
中管理这两个注入的方式
val module = module {
single(qualifier = qualifier("single1")) { Logger() }
single(qualifier = qualifier("single2")) { Logger() }
viewModel { KoinViewModel() }
viewModel { KoinParamsViewModel(get(qualifier = qualifier("single1"))) }
}
无论是无参还是有参的 ViewModel
都是通过 viewModel{}
扩展函数来注入,只不过有参的直接通过 get()
方法将参数传入即可,这个在前面的文章中也有提到,注入对象的参数不需要在获取的时候传入,只需要在 module
定义的时候直接绑定就行了,这样就可以做到我们只管拿来用,不用去管如何实现的。
最后我们再来看看如何获取和使用注入的 ViewModel
@Composable
fun Greeting(
name: String, modifier: Modifier = Modifier,
koinViewModel: KoinViewModel = org.koin.androidx.compose.koinViewModel(),
koinParamsViewModel: KoinParamsViewModel = org.koin.androidx.compose.koinViewModel()
) {
Text(
text = "Hello $name!",
modifier = modifier.clickable {
koinViewModel.print()
koinParamsViewModel.print()
}
)
}
#
KoinViewModel print
Logger print: KoinParamsViewModel, 69574952
想要获取ViewModel
对象,只需要调用 koinViewModel()
方法就好,不用管是否有参数需要传递,Koin 会自动为我们将所需要的参数赋值过去,通过后面日志也可以表示我们 ViewModel
对象注入成功了。
其实在 Compose 工程中,Koin 只是简单的增加了一些特殊的注入方法,帮助我们更好的管理和使用注入对象,好了,到此为止 Koin 在 Compose 中如何使用依赖注入已经介绍完了,大家感兴趣的可以在 Demo 中体验体验下 Koin 的魅力!
一起成长!?