Koin 是什么

Koin 是为 Kotlin 开发者提供的一个实用型轻量级依赖注入框架,采用纯 Kotlin 语言编写而成,仅使用功能解析,无代理、无代码生成、无反射。

官网地址

优势

依赖注入好处

  • 增加开发效率、省去重复的简单体力劳动

    首先new一个实例的过程是一个重复的简单体力劳动,依赖注入可以把new一个实例的工作做了,因此我们把主要精力集中在关键业务上、同时也能增加开发效率上。
  • 代码更具可读性
  • 省去写单例的方法
  • 解耦

    假如不用依赖注入的话,一个类的new代码是非常可能充斥在app的多个类中的,假如该类的构造函数发生变化,那这些涉及到的类都得进行修改。

和dagger相比

  1. 编译生成的代码少
  2. 编译时间少
  3. 上手简单

使用方法

1.添加依赖

// Add Jcenter to your repositories if needed
repositories {
jcenter()
}
dependencies {
// Koin for Android
compile "org.koin:koin-android:$koin_version"
}

2.比如创建一个HelloRepository来提供一些数据:

interface HelloRepository {
fun giveHello(): String
} class HelloRepositoryImpl() : HelloRepository {
override fun giveHello() = "Hello Koin"
}

3.创建一个presenter类,用来使用这些数据:

class MySimplePresenter(val repo: HelloRepository) {

    fun sayHello() = "${repo.giveHello()} from $this"
}

4.编写Koin模块,使用该module函数声明模块。

val appModule = module {

    // single instance of HelloRepository
single<HelloRepository> { HelloRepositoryImpl() } // Simple Presenter Factory
factory { MySimplePresenter(get()) }
}

factory每次Activity需要一个实例时都会创建一个新实例。

single 区别在于其提供的实例是单例的

get()这里的功能是直接检索实例(非延迟)

5.启动koin

现在有了一个模块,只需要在Application里调用startKoin()函数:

class MyApplication : Application(){
override fun onCreate() {
super.onCreate()
// Start Koin
startKoin{
androidLogger()
androidContext(this@MyApplication)
modules(appModule)
}
}
}

6.注入依赖

该MySimplePresenter组件将使用HelloRepository实例创建。用by inject()委托注入器注入它:

class MySimpleActivity : AppCompatActivity() {

    // Lazy injected MySimplePresenter
val firstPresenter: MySimplePresenter by inject() override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) //...
}
}

该by inject()功能使我们能够在Android组件运行时(活动,片段,服务…)中检索Koin实例。

原理

内联函数

  • Koin使用了很多的内联函数,它的作用简单来说就是方便进行类型推导,能具体化类型参数。
  • 被inline标记的函数就是内联函数,其原理就是:在编译时期,把调用这个函数的地方用这个函数的方法体进行替换
fun <T> method(lock: Lock, body: () -> T): T {
lock.lock()
try {
return body()
} finally {
lock.unlock()
}
} method(lock, {"我是body方法体"})//lock是一个Lock对象

其实上面调用的方法,在编译时期就会把下面的内容替换到调用该方法的地方,这样就会减少方法压栈,出栈,进而减少资源消耗;

        lock.lock()
try {
return "我是body方法体"
} finally {
lock.unlock()
}

也就是说inline关键字实际上增加了代码量,但是提升了性能,而且增加的代码量是在编译期执行的,对程序可读性不会造成影响

Reified

  • 由于 Java 中的泛型存在类型擦除的情况,任何在运行时需要知道泛型确切类型信息的操作都没法用了。比如你不能检查一个对象是否为泛型类型 T 的实例,所以需要反射。
  • 而reified,字面意思:具体化,,其实就是具体化泛型。
  • 主要还是有内联函数inline,才使得kotlin能够直接通过泛型就能拿到泛型的类型,只有内联函数的类型参数可以具体化。

例子

定义实现一个扩展函数启动 Activity,一般都需要传 Class 参数:

// Function
private fun <T : Activity> Activity.startActivity(context: Context, clazz: Class<T>) {
startActivity(Intent(context, clazz))
} // Caller
startActivity(context, NewActivity::class.java)

使用 reified,通过添加类型传递简化泛型参数

// Function
inline fun <reified T : Activity> Activity.startActivity(context: Context) {
startActivity(Intent(context, T::class.java))
} // Caller
startActivity<NewActivity>(context)

注入流程

  • 内联函数支持具体化的类型参数,使用 reified 修饰符来限定类型参数,可以在函数内部访问它,由于函数是内联的,所以不需要反射。
  • koin里有一个全局的容器,提供了应用所有所需实例的构造方式,那么当我们需要新建实例的时候,就可以直接从这个容器里面获取到它的构造方式然后拿到所需的依赖,构造出所需的实例就可以了。
startKoin(this, appModule, logger = AndroidLogger(showDebug = BuildConfig.DEBUG))
  • Koin提供一个全局容器,将所有的依赖构造方式转换成 BeanDefinition 进行注册,这是一个HashSet,名字是 definitions。

BeanDefinition

  • name以及primaryType,这两个是get()关键字依赖检索所需的key。
  • definition: Definition,它的值代表了其构造方式来源于那个module,对应前文的appModule,通过它可以反向推导该实例需要哪些依赖。
  override fun <T> get(parameters: ParameterDefinition): Instance<T> {
val needCreation = instance == null
if (needCreation) {
instance = create(parameters)
}
return Instance(instance as T, needCreation)
} fun <T> create(parameters: ParameterDefinition): T {
try {
val parameterList = parameters()
val instance = bean.definition.invoke(parameterList) as Any
instance as T //创建参数的实例
return instance
} catch (e: Throwable) {
// ....
}
}

总结

  • 现在需要一个 MainViewModel 的实例,那么通过clazz为Class的key在definitions中进行查找。
  • 查到有一个 MainViewModel 的 BeanDefinition,通过注册过的 definition: Definition找到其构造方式的位置(module)。
  • 当通过 MainViewModel(get() 的构造方式去构造 MainViewModel 实例的时候,发现又有一个get(),然后就是再重复前面的逻辑,一直到生成ViewModel实例为止。

示例代码

放弃dagger?Anrdoi依赖注入框架koin的更多相关文章

  1. [Android]依赖注入框架google的dagger

    分享一下Android依赖注入框架--Google升级版Dagger2框架 Google的Dagger2是对上一版squareup的Dagger改版,话不多说直接上项目代码. Dagger2源码 Da ...

  2. [Android]依赖注入框架squareup的dagger

    分享一下Android依赖注入框架--Dagger使用 Dagger源码 Dagger1-Demo 希望能给大家的开发带来帮助.

  3. Android Dagger依赖注入框架浅析

    今天接触了Dagger这套android的依赖注入框架(DI框架).感觉跟Spring 的IOC差点儿相同吧.这个框架它的优点是它没有採用反射技术(Spring是用反射的),而是用预编译技术.因为基于 ...

  4. 简单谈谈Hilt——依赖注入框架

    今天继续Jetpack专题,相信不少的朋友都使用过Dagger,也放弃过Dagger,因为实在太难用了.所以官方也是为了让我们更好使用依赖注入框架,为我们封装了一个新的框架--Hilt,今天一起来看看 ...

  5. [Android]使用Dagger 2依赖注入 - DI介绍(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5092083.html 使用Dagger 2依赖注入 - DI介 ...

  6. [Android]使用Dagger 2依赖注入 - API(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5092525.html 使用Dagger 2依赖注入 - API ...

  7. 史上最好用的依赖注入框架Google Guice【转】

    Guice是Google开发的一个轻量级,基于Java5(主要运用泛型与注释特性)的依赖注入框架(IOC).Guice非常小而且快. (其他的依赖注入框架还有Dagger,Spring) Spring ...

  8. 依赖注入框架之dagger2

    主页: https://github.com/google/dagger 历史 * Dagger1是由Square公司受到Guice(https://github.com/google/guice)启 ...

  9. [Android]使用Dagger 2依赖注入 - 自定义Scope(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5095426.html 使用Dagger 2依赖注入 - 自定义 ...

随机推荐

  1. java面试基础必备

    一.Java基础 1. String类为什么是final的. 2. HashMap的源码,实现原理,底层结构. 3. 说说你知道的几个Java集合类:list.set.queue.map实现类咯... ...

  2. Halcon斑点分析BlobAnalysis解析

    斑点分析的算法非常简单:在图像中,相关对象的像素(也称为前景)通过其灰度值来识别.例如,图中示例显示了液体中的组织颗粒.这些粒子是明亮的,液体(背景)是暗的.通过选择明亮的像素(阈值),可以很容易检测 ...

  3. 入门大数据---HDFS,Zookeeper,ZookeeperFailOverController(简称:ZKFC),JournalNode是什么?

    HDFS介绍: 简述: Hadoop Distributed File System(HDFS)是一种分布式文件系统,设计用于在商用硬件上运行.它与现有的分布式文件系统有许多相似之处.但是,与其他分布 ...

  4. 入门大数据---安装ClouderaManager,CDH和Impala,Hue,oozie等服务

    1.要求和支持的版本 (PS:我使用的环境,都用加粗标识了.) 1.1 支持的操作系统版本 操作系统 版本 RHEL/CentOS/OL with RHCK kernel 7.6, 7.5, 7.4, ...

  5. PID各环节的意义和功能,自带PID的matlab编程实例

    这是PID的标准形式包括比例/积分/微分三部分,e为偏差 下面我们分析三个环节的作用,设:当前系统状态A,目标状态B, e=B-A,初始状态e>0 (以下是个人的理解,欢迎读者评论) 1 比例环 ...

  6. Java中的过滤器

    什么是过滤器(Filter)? 过滤器就是一个实现了特殊接口的Java类.实现对请求资源的过滤的功能. 过滤器是Servlet技术中最为实用的技术. 过滤器有啥用? 对目标资源进行过滤. 自动登录,解 ...

  7. Lists.newArrayList() 和 new ArrayList()的区别?

    什么是创建List字符串的最好构造方法?是Lists.newArrayList()还是new ArrayList()? 还是个人喜好? Lists和Maps是两个工具类, Lists.newArray ...

  8. windows10 通过vnc远程访问ubuntu16.04

    参考链接 链接1 , 链接2 ,链接3 . 0.前言: 为方便深度学习训练,我们需要多个windows的电脑可以远程访问一个linux系统的工作站(以方便在linux系统上进行深度学习训练) 前提: ...

  9. String 类的其他功能

    12.01_常见对象(Scanner的概述和方法介绍)(掌握) A:Scanner的概述 B:Scanner的构造方法 Scanner(InputStream source) System.in C: ...

  10. CSS 3中-webkit-, -moz-, -o-, -ms-这些私有前缀的含义和兼容

    css3作为页面样式的表现语言,增加了很多新的属性,但是部分css3属性在一些浏览器上还处于试验阶段,所以为了有效的显示css3的样式,对应不同的浏览器内核需要不同的前缀声明,例如: -moz- :F ...