依赖注入框架Koin详解

Koin框架,适用于使用Kotlin开发 ,是一款轻量级的依赖注入框架,无代理,无代码生成,无反射。

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

官方网站

GitHub

Application DSL

  • koinApplication { }       

用于创建KoinApplocation的实例配置

  • startKoin { }

 startKoin {
           this.androidContext(this@App)//koin获取context  
           
       }

创建一个KoinApplication 可以在其中使用GlobalContext  的Api  一般用作全局初始化

KoinApplication的一些配置

  • logger( )

描述要使用的Log 级别,默认使用EmptyLogger

  • modules( ) 

要加载的模块列表

  • properties()

放置所有的properties 参数为HashMap

可以使用KoinComponent 获取到koin对象,获取放置的Value

  • fileProperties( )

将给定文件的属性加载到Koin

  • environmentProperties( )

将属性从OS环境中加载到Koin

Global ,Local 

KoinApplication 可以通过koinApplication{} 和startKoin{}  两种方式创建这两种方式的区别:
 

/**
 * Create a KoinApplication instance and help configure it
 * @author Arnaud Giuliani
 */
fun koinApplication(appDeclaration: KoinAppDeclaration): KoinApplication {
    val koinApplication = KoinApplication.create()
    appDeclaration(koinApplication)
    return koinApplication
}

//koinApplication{}  这种方式只创建KoinApplication
/**
 * Start a Koin Application as StandAlone
 */
fun startKoin(appDeclaration: KoinAppDeclaration): KoinApplication {
    val koinApplication = KoinApplication.create()
    GlobalContext.start(koinApplication)
    appDeclaration(koinApplication)
    koinApplication.createEagerInstances()
    return koinApplication
}

   /**
     * Start a Koin Application as StandAlone
     */
    @JvmStatic
    fun start(koinApplication: KoinApplication) {
        if (app != null) {
            throw KoinAppAlreadyStartedException("A Koin Application has already been started")
        }
        app = koinApplication
    }

//startKoin{} 则执行了 GlobalContext.start(koinApplication)  

 

/**
 * KoinComponent interface marker to bring Koin extensions features
 *
 * @author Arnaud Giuliani
 */
interface KoinComponent {

    /**
     * Get the associated Koin instance
     */
    fun getKoin(): Koin = GlobalContext.get().koin

}

看源码发现 koinApplication{}  还需要调用 GlobalContext.start(koinApplication)  才能使用

Module DSL

  • module { // module content }

创建一个model,module 只是一个定义类型的逻辑空间,所以不同module 也可以使用get()

Module中可以使用的方法:

  • factory { //definition }

提供一个工厂(每次注入都会创建新的) Bean

  • single { //definition }

创建一个单例的Bean 也可以通过不同的别名去声明不同一种类型的Bean

  • get()

用于解决组件之间的依赖关系,也可以使用name ,scope,parameters 

// Presenter <- Service
class Service()
class Controller(val view : View)

val myModule = module {

    // declare Service as single instance
    single { Service() }
    // declare Controller as single instance, resolving View instance with get()
    single { Controller(get()) }
}

//get() 方法使用获取了 声明的Service()  

 

  • bind()

为给定的bean定义添加要绑定的类型

 

// Service interface
interface Service{

    fun doSomething()
}

// Service Implementation
class ServiceImp() : Service{

    fun doSomething() { ... }
}
val myModule = module {

    // Will match types ServiceImp & Service
    single { ServiceImp() } bind Service::class
}
// bind 方法  可以让ServiceImp  和 Service  绑定
这样你inject  ServiceImp   也可以 inject   Service  
  • binds()

为给定的bean定义添加类型数组

  • scope { // scope group }

为范围定义定义逻辑组

  • scoped { //definition }

提供仅存在于scope内的bean定义

single{} factory{} scoped{} 都可以使用lambda 表达式来声明 lambda 的返回值类型就是声明的类型

Koin 不允许同一名称的同一类型声明多次,你可以为同一种类型声明两个定义:

val myModule = module {
    single(named(name = "default")) { ServiceImpl() }
    single(named(name = "test")) { ServiceImpl() }
}

val service : Service by inject(name = "default")

也可以这样

val myModule = module {
    single { ServiceImpl1() }
    single(named(name = "test")) { ServiceImpl2() }
}

val service : Service by inject() //默认注入的是 ServiceImpl1

声明注入参数

class Presenter(val view : View)

val myModule = module {
    single{ (view : View) -> Presenter(view) }
}
//在single factory scope 中可以使用这种方式来注入参数

与已声明的类型不同,注入参数是通过解析inject传递的参数来注入

val presenter : Presenter by inject { parametersOf(view) }
//使用paramtersOf

Koin  提供了一些定义标志

  • createAtStart

声明一个类型或module 在什么时候创建(使用时 or 开始) false 使用时再创建,true startKoin 就创建

val myModule = module {
 // 声明Service 类型在开始就创建
    single(createAtStart=true) { TestServiceImp() }
}

   
val myModuleB = module(createAtStart=true) {

    single{ TestServiceImp() }
}
  •  override

Koin 不允许同一名称同一类型声明多次,当你需要声明多次时,你可以使用override 

val helloModule = module {
    single { "a" }
    single(override = true) { "b" }
    single(override = true) { "c"}

}
fun main(args: Array) {

    startKoin {
            modules(helloModule)
        }

    print(Test().str)//c

}

class  Test:KoinComponent{
    val str by inject ()

}

处理泛型

module {
    single { ArrayList() }
    single { ArrayList() }
}
/*Already existing definition or try to override an existing one: [type:Single,class:'java.util.ArrayList']*/

//这样会抛出异常
val helloModule = module {
    single(named(name = "Ints")) { ArrayList() }
    single(named(name = "Strings") ) { ArrayList() }

} 
//这样就可以了

需要实现注入必须实现KoinComponent 接口

你可以使用get() & inject() 实现注入

//非懒加载
 val str : String = get()
//懒加载,在用到的时候才注入
 val str2:String by inject()

 

 

 

你可能感兴趣的:(Android学习笔记)