Koin是一款轻量级的依赖注入框架,根据官方的描述,它无代理,无代码生成,无反射。
第一步:Gradle Setup
// Add Jcenter to your repositories if needed
repositories {
jcenter()
}
dependencies {
// Koin for Android
compile "org.koin:koin-android:1.0.1"
// Koin Android Scope feature
compile "org.koin:koin-android-scope:1.0.1"
// Koin Android ViewModel feature
compile "org.koin:koin-android-viewmodel:1.0.1"
}
第二步:使用 Koin 之前,先建立一个依赖对象
import com.jastzeonic.koinsample.model.Dog
import org.koin.dsl.module.module
val creatureModule = module {
factory {
Dog()
}
}
第三步:初始化
自然的,我们得告诉koin它需要这个module,这就是所谓的初始化,时机就是app诞生时,所以要在application中来做startkoin初始化的动作。
mport org.koin.android.ext.android.startKoin
class CreatureApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin(this,listOf(creatureModule))
}
}
第四步:注入
然后我们再来看怎么inject给依赖者,
class CreatureActivity : AppCompatActivity() {
//Just use val and by inject
private val creature:Dog by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_creature)
Glide.with(this).load(creature.image())
.into(creature_image)
creature_image.postDelayed({
Toast.makeText(this.applicationContext, creature.shout(), Toast.LENGTH_LONG).show()
}, 500)
}
}
或者可以写成:
class CreatureActivity : AppCompatActivity() {
private lateinit var creature:Dog
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_creature)
creature = get()
Glide.with(this).load(creature.image())
.into(creature_image)
creature_image.postDelayed({
Toast.makeText(this.applicationContext, creature.shout(), Toast.LENGTH_LONG).show()
}, 500)
}
}
考虑一种情况:假如 Activity 的依赖对象 Presenter 也依赖着另一个依赖对象 Repository ,使用 Koin 则会写成这样:
val appModule = module {
single{ Repository() }
factory{ Presenter(get())}
}
以上的写法,在编译前就决定好依赖的是哪个类型 了,如果希望在Runtime时决定要inject什么类型呢 ?
val creatureModule = module {
factory { (creatureType: Int) ->
when (creatureType) {
Creature.TYPE_DOG -> Dog()
Creature.TYPE_CAT -> Cat()
else -> {
Dog()
}
}
}
}
class CreatureActivity : AppCompatActivity() {
companion object {
const val CREATURE_TYPE = "creature_type"
}
private lateinit var creature: Creature
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_creature)
val creatureType = intent.getIntExtra(CREATURE_TYPE, 0)
// Injection parametersOf(...)
creature = get { parametersOf(creatureType) }
Log.v("tag", "CreatureActivity$creature")
Glide.with(this).load(creature.image())
.into(creature_image)
creature_image.postDelayed({
Toast.makeText(this.applicationContext, creature.shout(), Toast.LENGTH_LONG).show()
}, 500)
}
}
还有几件事:
factory
用到的时候就新建一个
Scope
希望能够在某个Activity上让两个以上的Fragment共用,可以这样使用:
val creatureModule = module {
scope("DogSession") {
Dog()
}
}
class ScopeDemoActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_scope_demo)
bindScope(createScope("DogSession"))
}
}
这样在Fragment里面就可以正常的inject
class FragmentA : Fragment() {
private val dog: Dog by inject()
...
}
class FragmentB : Fragment() {
private val dog: Dog by inject()
...
}
在两个activity之间公用这个实例,写法如下:
getKoin().createScope("DogSession")
然後在兩個 Activity 裡面 inject:
class MyActivity1 : AppCompatActivity() {
val dog : Dog by inject()
}
class MyActivity2 : AppCompatActivity() {
val dog : Dog by inject()
}
single :
直到 App 結束前都會一直存在
val creatureModule = module {
single {
Dog()
}
}