说到依赖注入框架,Android开发者一定最先想到dagger2,但是dagger2是Java的产物,Android的开发语言已经向kotlin切换,虽然Java与kotlin是完全兼容的,但是基于kotlin语言的一些优异特性一定能诞生出许多更适用于kotlin语言环境的新的框架来,koin正是其中一个。
- 什么是Koin?
Koin是用于Kotlin开发人员(实际也可用于Java开发中)的实用轻量级依赖注入框架。用纯Kotlin编写,仅使用方法来解决问题:无代理,无代码生成,无反射。Koin是一个DSL,一个轻量级容器和一个实用的API。
github地址:https://github.com/InsertKoinIO/koin
- 如何在项目中使用:
将koin-core依赖项添加到Gradle项目
// Add Jcenter to your repositories if needed
repositories {
jcenter()
}
dependencies {
// Koin for Android
implementation 'org.koin:koin-android:1.0.2'
}
得益于Kotlin语言的强大功能,koin提供了一个DSL(domain-specific language)来帮助我们描述应用,而不是添加注解或为其生成代码。这些注解最终还是需要代码来分析,从而进行(动态)代理或者生成代码。而使用Kotlin DSL,我们可以使用智能功能API来实现相同的目标:进行依赖注入。
Koin的使用非常简单,下面我们通过一个实例来展示如何快速注入:
首先我们创建一个接口
interface LoginService {
fun login()
fun unLogin()
}
接着我们创建接口的实现
class LoginServiceImpl:LoginService {
override fun login() {
println("login")
}
override fun unLogin() {
println("unLogin")
}
}
然后我们声明这个组件
class KoinApplication: Application() {
private val loginModule = module {
single<LoginService> { LoginServiceImpl() }//以单例模式声明将这个组件定义绑定到LoginService
}
override fun onCreate() {
super.onCreate()
startKoin(this, arrayListOf(loginModule))//将声明的组件注册到koin
}
}
接下来我们就可以使用koin来为我们注入组件了
只要在要使用的Activity,Fragment等应用组件中添加如下注入声明
private val loginService: LoginService by inject()
koin会通过懒加载的方式,在使用该实例时为我们注入LoginServiceImpl的实例。
当然也可以不通过懒加载,直接获得实例
private val loginService: LoginService = get()
当然,组件定义也可以是带参数的
private val loginModule = module {
single<LoginService> { (code: String) ->LoginServiceImpl(code) }//声明将这个组件定义绑定到LoginService
}
在注入时,传入注入所需参数即可
private val loginService: LoginService by inject { parametersOf("123") }
全部调用代码:
class MainActivity : AppCompatActivity() {
private val loginService: LoginService by inject { parametersOf("123") }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loginService.login()
loginService.unLogin()
}
}
熟悉依赖注入框架的朋友可能都知道,在Java中,依赖注入通常使用注解,依靠动态代理,或者apt,或者反射来实现注入功能,那么koin不依靠上面的技术是如何做到这一切的呢。
答案就是依靠kotlin特有的特性扩展函数,当然也得益于kotlin对于函数式编程的支持,让koin的代码更加简洁。
将组件注册到容器中后,其原理为将一个组件实例化的方法实例,存储在容器中。
在调用inject()注入的时候,通过组件的定义(单例还是factory),以及绑定的类型(实例化方法绑定到哪个接口或者类型)匹配到对应的生成器(注册的实例化方法),然后通过扩展函数的形式,在Android组件(Activity,Fragment等)中实例化注入。
这里的inject方法是ComponentCallbacks接口的扩展函数,而ComponentCallbacks是所有Android应用组件都继承的几口,所以,能在ComponentCallbacks的实现组件中进行inject注入。
这种新的依赖注入方式,也为我们项目中的架构优化提供了更多的想象空间。
比如对于网络请求,可以让具体的请求方式与业务调用隔离。
这种思想类似于服务开发,只需要向外暴露出使用的接口,具体实现方案调用方并不用关心。