koin的使用
添加依赖库
implementation 'org.koin:koin-androidx-viewmodel:2.0.1'
implementation 'org.koin:koin-android:2.0.1'
需要创建依赖对象
这里创建三个类,Student,SchoolCourse,Friend。
- Student类
依赖于SchoolCourse,Friend类的方法。
class Student(val course: SchoolCourse,val friend: Friend) {
fun beSmart() {
course.study()
friend.hangout()
}
}
- SchoolCourse类
提供方法 study 负责打印 “I am studying”
class SchoolCourse {
fun study() {
println("I am studying")
}
}
- Friend 类
提供方法 hangout 负责打印 “We’re hanging out”
class Friend {
fun hangout() {
println("We're hanging out")
}
}
定义依赖集合
创建 Modeles 文件
- 需要使用 module 方法
提供所需要的依赖
- 需要 signle 方法
使当前依赖为一个单例的对象
- 需要 factory 方法
定义一个工场每次调用创建一个新的实例
- 需要 get() 方法
get 用于最终实现注入
val appModule: Module = module {
single { SchoolCourse() }
factory { Friend() }
factory { Student(get(), get()) }
}
启动 Koin
需要系统在创建时第一个启动Application实例
修改 application 中的 name 属性 使得应用第一个启动它
- 需要创建 MyApp
第一个启动的Application实例
- 需要 startKoin
用来启动Koin
- 需要 modules
注册声明的Module
- 需要 androidContext
向Koin中注入context
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@MyApp)
modules(listOf(appModule))
}
}
}
使用 koin 实现注入
在需要注入的地方使用
- 需要使用 get()
非 懒加载,注入实例
通过 注入依赖完成后的实例调用beSmart()方法
val student = get<Student>()
student.beSmart()
val student2 = get<Student>()
student2.beSmart()
完成注入
什么是 koin?
一个轻量级的依赖注入组件。
补充
Get
get()用于实现注入。
当你所属类型不确定时,可以指定类型。get
声明:绑定一个接口
一个 single 或者 factory 声明将会使用其给定的 lambda 表达式类型。比如 single{T},该声明所匹配的类型就是表达式所声明的类型 T 让我们以一个类及其实现的接口为例:
// Service interface
interface Service{
fun doSomething()
}
// Service Implementation
class ServiceImp() : Service {
fun doSomething() { ... }
}
在koin模块(module),我们可以使用Kotiln下的 as 操作符。如下所示:
val myModule = module {
// 只匹配 Service 类型
single { ServiceImp() }
// 只匹配 Service 类型
single { ServiceImp() as Service }
}
你也可以使用推断类型表达式
val myModule = module {
// 只匹配 Service 类型
single { ServiceImp() }
// 只匹配 Service 类型
single<Service> { ServiceImp() }
}
第二种风格是首选的,在接下来的文档中,也会使用该方法。
Bind
bind()
- 为给定的对象声明添加要绑定的类型Bind 是一个中辍函数,可以用于把一个Service关联到多个类。例如现在有两个接口:Tool,Flammable,Stove实现了这两个接口。显然如果只定义1个Service是不能同时注入Stove和这两个接口的。
这是就可以发挥Bind的作用了
val myModule = module{ factory { Stove() } bind Tool::class bind Flammable::class // <- here! factory { Chef(get()) } }
这么一来,下面的三个注入都是合法的,并都会得到一个 Stove 实例:
val chef: Chef = get() val tool:Tool = get() val flammable:Flammable = get()
named
限定符,用来区别同一个类的不同实例
使用
single(named("dev")) { DataRepository() }
single(named("test")) { DataRepository() }
name 属性
可通过name或者class检索到对应的实例
使用
factory(name = MAIN) {
AndroidSchedulers.mainThread()
}
依赖注入和控制反转
依赖注入(Dependency Injection,简称 DI)
什么是依赖注入?
假设 A 是 耳机,B 是播放器。
当 A 依赖 B 时(也就是耳机需要播放以音乐时),A 要想播放音乐就必须要有B的实例,也就是
- 通过A的接口,把B传入;
- 通过A的构造,把B传入;
- 通过A的属性,把B传入;
这些过程叫做依赖注入(DI)
控制反转(Inversion of Control,简称 Ioc)
但是 A 并不能控制 B 何时播放(创建)或者关闭(销毁),仅使用 B ,那么 B 的控制权交给 A 之外的事务处理,这些叫做 控制反转(Ioc)
为什么需要依赖注入
降低耦合
什么是耦合
耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。两个或多个功能模块之间的关联程度。
什么是解耦
解除类(模块)之间的直接关系,将直接关系转换成间接关系
引用: