当前位置: 首页 > 工具软件 > Koin > 使用案例 >

Kotlin替换Dagger2/Hilt的依赖注入框架--Koin。

楚丰羽
2023-12-01

Koin、Dagger2、Hilt 目前都是非常流行的库,面对这么多层出不穷的新技术,我们该做如何选择,是一直困扰我们的一个问题。

  • Hilt 与 Dagger2 区别并不大,Hilt就是对Dagger2的封装。
  • Koin框架,适用于使用Kotlin开发 ,是一款轻量级的依赖注入框架,无代理,无代码生成,无反射。

相对于Dagger2 而言Koin更加适合Kotlin语言。

Koin官网:https://start.insert-koin.io/#/quickstart/kotlin
GitHub:https://github.com/InsertKoinIO/getting-started-koin-core

https://github.com/Pangu-Immortal

在项目中使用 Koin

如果要在项目中使用 Koin,需要在项目中添加 Koin 的依赖,我们只需要在 App 模块中的 build.gradle 文件中添加以下代码。

implementation “org.koin:koin-core:2.1.5”
implementation “org.koin:koin-androidx-viewmodel:2.1.5”

如果需要在项目中使用 Koin 进行依赖注入,需要在 Application 或者其他的地方进行初始化。

class KoinApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        startKoin {
            AndroidLogger(Level.DEBUG)
            androidContext(this@KoinApplication)
            modules(appModule)
        }
    }
}

当初始化完成之后,就可以在项目中使用 Koin 了,首先我们来看一下如何在项目中注入 Repository, Repository 有一个子类 TasksRepository,代码和上文介绍的一样,需要在其构造函数构造 localDataSource 和 remoteDataSource 两个 DataSource。

class TasksRepository @Inject constructor(
    private val localDataSource: DataSource,
    private val remoteDataSource: DataSource
) : Repository

那么在 Koin 中如何注入呢,很简单,只需要几行代码就可以完成。

val repoModule = module {
    single { LocalDataSource(get()) }
    single { RemoteDataSource() }
    single { TasksRepository(get(), get()) }
}
// 添加所有需要在 Application 中进行初始化的 module
val appModule = listOf(repoModule)

和上面 Hilt 长长的代码比起来,Koin 是不是简单很多,那么 Room、Retrofit、ViewModel 如何注入呢,也很简单,代码如下所示。

// 注入 ViewModel
val viewModele = module {
    viewModel { MainViewModel(get()) }
}

// 注入 Room
val localModule = module {
    single { AppDataBase.initDataBase(androidApplication()) }
    single { get<AppDataBase>().personDao() }
}

// 注入 Retrofit
val remodeModule = module {
    single { GitHubService.createRetrofit() }
    single { get<Retrofit>().create(GitHubService::class.java) }
}

// 添加所有需要在 Application 中进行初始化的 module
val appModule = listOf(viewModele, localModule, remodeModule)

上面 Koin 的代码严格意义上讲,其实不太规范,在这里只是为了和 Hilt 进行更好的对比。

到这里是不是感觉 Hilt 相比于 Koin 是不是简单很多,在阅读 Hilt 文档的时候花了很长时间才消化,而 Koin 只需要花很短的时间。

不仅仅如此而已,根据 Koin 文档介绍,Koin 不需要用到反射,那么无反射 Koin 是如何实现的呢,因为 Koin 基于 kotlin 基础上进行开发的,使用了 kotlin 强大的语法糖(例如 Inline、Reified 等等)和函数式编程,来看一个简单的例子。

inline fun <reified T : ViewModel> Module.viewModel(
    qualifier: Qualifier? = null,
    override: Boolean = false,
    noinline definition: Definition<T>
): BeanDefinition<T> {
    val beanDefinition = factory(qualifier, override, definition)
    beanDefinition.setIsViewModel()
    return beanDefinition
}

内联函数支持具体化的类型参数,使用 reified 修饰符来限定类型参数,可以在函数内部访问它,由于函数是内联的,所以不需要反射。

但是在另一方面 Koin 相比于 Hilt 错误提示不够友好,Hilt 是基于 Dagger 基础上进行开发的,所以 Hilt 自然也拥有了 Dagger 的优点,编译时正确性,对于一个大型项目来说,这是一个非常严重的问题,因为我们更喜欢编译错误而不是运行时错误。

总结

我们总共从以下几个方面对 Hilt 和 Koin 进行全方面的分析:

  1. AndroidStudio 支持 Hilt 在关联代码间进行导航,支持在 @Inject 修饰的构造器、@Binds 或者@Provides 修饰的方法、限定符之间进行跳转。
  2. 项目结构:完成 Hilt 的依赖注入需要的文件往往多于 Koin。
  3. 代码行数:使用 Statistic 工具来进行代码统计,反复对比了项目编译前和编译后,Hilt 生成的代码多于 Koin,随着项目越来越复杂,生成的代码量会越来越多。
  4. 编译时间:Hilt 编译时间总是大于 Koin,这个结果告诉我们,如果是在一个非常大型的项目,这个代价是非常昂贵。

使用上对比:Hilt 使用起来要比 Koin 麻烦很多,其入门门槛高于 Koin,在阅读 Hilt 文档的时候花了很长时间才消化,而Koin 只需要花很短的时间,依赖注入部分的代码 Hilt 多于Koin,在一个更大更复杂的项目中所需要的代码也更多,也越来越复杂。

https://github.com/Pangu-Immortal

 类似资料: