放弃dagger?Anrdoi依赖注入框架koin

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。
    UhlZpF.png

BeanDefinition
UhlM01.png

  • 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实例为止。

示例代码

本文转载于网络 如有侵权请联系删除

相关文章

  • go web: 2 封装日志包log

    在web项目中,记日志是非常重要的。所以,我做的第一件事,就是向log包动手。 和Python相比,log包功能上逊色不少,但它给我们提供了基础的构架,让我们能自己稍微封装下。需求对日志包我的要求很低,只要满足: 1.提供Error,Info方法即可 2.日志按天分割,即每隔一天,把昨天的日志保存为logname.20170823这样的文件代码在原来的基础上,我们在src中创建文件夹logger,在里面创建文件logger.go 现在文件结构如下:src--| handlers--| test--| test.go logger--| logger.go | main.go复制这个文件代码有点长,所以放附录了。 要使用,只需要在main.go里调用:logger.InitLogging("8080",logger.DEBUG) logger.Error("%s%s","hi","myboy")复制然后,在bin文件的同级,手工创建logs文件夹。运行程序,日志功能就开始执行了。 测试了一下效率,在macpr

  • 从CL210 OpenStack考试看Neutron网络

    本文为笔者阅读大量文档和做实验的心得。本文不包含任何认证考试解密内容,如想系统性学习红帽OpenStack,请联系红帽公司培训部门。CL210考试环境  笔者在今年参加了OpenStackCL210培训。但是对培训过程中实验环境的网络拓扑当时没有弄明白,后来看了一些资料,总算有了大概的了解。  书上实验的拓扑图见上图。乍一看,是不是有点复杂?  在实验中,每个人分配了一个台式机,台式机是一个RHEL操作系统。通过里面的KVM虚拟化,虚拟出了两个虚拟机Server-a和Server-b。Server-a有两个网卡:eth1和eth2。后来我们做的事情,是在Server-a上以All-in-one的方式安装OpenStack,第二个实验是将ServerB作为Nova-Compute加入到OpenStack中。  当server-a上的openstack安装好以后,创建的虚拟机实例就是基于serveraRHEL中的KVM做的。也就是说,最终我们创建的openstack实例,实际上的三层嵌套虚拟化。  谈到OpenStack的网络,很多人不是很了解细节,但vSphere的网络大家都比较了解,下

  • 都9102年了还在用网页发邮件?

    哈喽!各位小伙伴大家好呀!本期给大家介绍一下如何使用邮件客户端收发邮件。其实现在大多数人上班都是使用客户端收发邮件, 只有少部分的人还在使用网页来收发邮件。 这篇文章主要还是写给还在网页发邮件的朋友, 希望你也加入到使用邮件客户端的行列。为啥要用客户端呢? 网页邮箱就算你设置了保存密码, 并把网址保存在了收藏夹, 但是每次打开都需要开浏览器,且浏览器需要一直打开当前页面。网页邮箱好是好,只是毕竟依赖网络, 一旦断网,你就查不了历史的邮件,写不了草稿,也无法定时发送,而客户端会把你的邮件全部下载到本地保存, 随时随地都能查,放在自己硬盘里毕竟会安心点。 还有就是多个邮箱的问题了, 当你有多个邮箱时,每个邮箱都要开一个浏览器页面来收信,真的很占用系统资源。如果是客户端话就方便多了可以同时管理多个邮箱账号, 设置自动启动,自动收信, 新邮件弹出提醒,也可以设置新邮件提示音。大部分的邮箱客户端占用资源都很小,至少比浏览器小,而且还有很多网页邮箱没有的功能,比如附件提醒,你在写信时忘了添加附件,但是你的信中写了“附件”两个字,你在点发送时客户端就会提醒你没有添加附件。 说的再好,不如下载一个客户

  • 【译】Redux + React 应用程序架构的 3 条规范(内附实例)

    原文地址:http://jaysoo.ca/2016/02/28/organizing-redux-application/Asourapplicationsgrow,weoftenfindthatfilestructureandorganizationtobecrucialforthemaintainabilityofapplicationcode. 随着应用程序的增长,通常我们就会发现文件结构和组织对于应用程序代码的可维护性来说就会变得非常重要。WhatIwanttodointhispostistopresentthreeorganizationalrulesthatIpersonallyfollowonmyownprojects.Byfollowingtherules,yourapplicationcodeshouldbeeasiertoreasonabout,andyouwillfindyourselfwastinglesstimeonfilenavigation,tediousrefactoring,andbugfixes. 在这篇文章里,我会介绍自己在项目中亲自实践的三条组

  • MathUtility类实现—C++

    这具体是什么类早已忘却,根据当年的注释里面有如下几个功能:实现float,int,double类型的max,min,abs函数。实现计算圆形面积,球体体积的函数。实现计算矩形面积,长方体的函数。/* 功能:实现MathUtility类 作者:windCoder 日期:2013-11-07 */ #include<iostream> usingnamespacestd; /************************************************************************ 功能:实现float,int,double类型的max,min,abs函数。 ************************************************************************/ classComplex { public: Complex(intaX,intaY,floatiX,floatiY,doublerX,doublerY); Complex(); ~Complex(); intmax(intaX,

  • 【深度解析】谷歌搜索算法如何排名医疗广告?

    【新智元导读】青年魏则西的不幸病逝激起了国内公众对搜索引擎虚假医疗网络广告问题的热议。提到搜索引擎,必须想到谷歌,那么谷歌是如何处理医疗广告的呢,答案是使用机器学习的RankBrain算法。 青年魏则西的不幸病逝,激起了国内公众对搜索引擎虚假医疗网络广告问题的热议。根据《商业价值》微信公众号今日文章《谷歌也曾涉足医疗广告,美国司法是如何监管的呢?》,可以发现在谷歌搜索“滑膜肉瘤”也会出医疗广告,但都有明显的“Ad”标识。同时,与百度相比,谷歌的付费广告并不影响排名。谷歌关于滑膜肉瘤治疗的搜索广告,有明确的广告标志。来源:商业价值 此外,《商业价值》文中提到,根据谷歌的搜索广告政策,要投放药品广告需要获得FDA以及美国药房理事会(NABP)认证。也就是说,只有获得政府审批的正规网上药店、药品与治疗才能在网站投放药品类广告。同时,谷歌的自动广告过滤机制,在很大程度上也能有效杜绝虚假医疗广告出现。根据谷歌发布的报告,他们2015年总计预先屏蔽了7.8亿条违规广告,封杀21.4万家广告商,其中包括1250万条违规的医疗和药品广告,涉及药品未获批准或者虚假误导性宣传等原因。谷歌如何用算法排名据统

  • 数十万人的黑产帝国DDoS,年产值超100亿

    陈梦腾讯安全平台部高级安全产品经理【谁坑了创业者的钱2】  创业的路上千难万险,一不留神就会尸骨无存。在过去的十年,腾讯安全积累了丰富对抗经验和方法。然而,我们要如何开放十年的积累,能够为这些优秀的企业做点什么,这就是腾讯安全未来的方向——专业、服务、分享。  █什么是DDoS?“你开了一间饭馆,我花钱雇了很多人冲进你的饭馆,占了你的餐位,纠缠你的服务员,但就是不点吃的。这样一来,真正想消费的顾客进不去,你就没有办法提供服务。”----DDoS  每次讲到DDoS都要重复啰嗦这一段,大家可能都听烦了。那我们就直接进入下一个话题。  █为什么创业者容易成为攻击目标?  DDoS发展至今天,他的获利途径可以说是复杂的。而创业者变成主要被攻击的对象之一,主要原因是因为这些企业大多未能构建成熟的防御体系,坏人攻击成本小,而获利途径,大多为商业竞争和敲诈勒索。下面给大家详细介绍。 1、商业恶性竞争  商业竞争在互联网这个万亿市场中尤为激烈。一些行业竞争者甚至为了利益不择手段、不顾法纪,通过DDoS攻击妨碍竞争对手的业务活动,打击对手的声誉,从中获取竞争优势。其中,电商行业和在线游戏行业是重灾区。

  • 从微信小程序,感受下极简设计是一种怎样的体验?

    一、产品特质决定产品所在行业,所在用户群体,产品本身的规模等等都决定了这个产品特质。1、产品所在领域产品所在行业领域决定了产品市场的大小,切入用户群的规模。产品所在领域的延展性,这些产品本生的领域价值会限制产品极简设计的流程。2、产品经理本生的价值产品经理本生的文艺价值和理性价值决定了产品特质。特别是像马扎、乔布斯这类人,对于极简设计的追求,才完成了强大的产品。小龙哥也是具备这种极简能力设计的产品经理。还有就是本生对于产品敏锐度,产品生活气息等等都会决定产品特质。二、抽象细化场景1、场景穷举设计产品时,会对线上场景和线下场景进行穷举。穷举中,通常去找到主流程。如果有主流程,则去对主流程每一个场景进行穷举。穷举过程中,要对反向的场景也要进行穷举。2、场景梳理穷举场景后,对场景进行梳理。梳理场景过程中,是对于场景思考的细节化。包括该场景是否存在,是否合理?场景下所在的流程,用户需要解决什么问题,在这个问题中,我们应该给予什么样的答案?3、场景细化场景梳理完成后,就是极简设计的点,对场景进行简化。比如,以前线下是微信公众号需要关注,关注完了之后,进入主页,主页有一个推送,然后点击链接进入H5

  • waitforsingleobject的作用_效率理论

    大家好,又见面了,我是你们的朋友全栈君。 MicrosoftWindows平台中两种最常用的锁定方法为WaitForSingleObject和EnterCriticalSection。WaitForSingleObject是一个过载MicrosoftAPI,可用于检查和修改许多不同对象(如事件、作业、互斥体、进程、信号、线程或计时器)的状态。WaitForSingleObject的一个不足之处是它会始终获取内核的锁定,因此无论是否获得锁定,它都会进入特权模式(环路0)。此API还进入Windows内核,即使指定的超时为0,亦如此。此锁定方法的另一不足之处在于,它一次只能处理64个尝试对某个对象进行锁定的线程。WaitForSingleObject的优点是它可以全局进行处理,这使得此API能够用于进程间的同步。它还具有为操作系统提供锁定对象信息的优势,从而可以实现公平性及优先级倒置。 通过对关键代码段实施EnterCriticalSection和LeaveCriticalSectionAPI调用,可以使用EnterCriticalSection。此API具有WaitForSingleO

  • Ternary Search Tree Java实现

    /** *@authorEdwinChen * */ //定义节点 classNode{ //存储字符串 charstoreChar; //是否完成单词 booleanisComplete; NodeleftChild,centerChild,rightChild; //构造方法 publicNode(charstoreChar,booleanisComplete){ this.storeChar=storeChar; this.isComplete=isComplete; } } publicclassTernarySearchTree{ //根节点 publicNoderoot; //存储结果 HashSet<String>result=newHashSet<String>(); //递归创建tree publicNodeinsert(Stringword,Nodenode,Integerindex){ if(word==null||"".equals(word)) returnnull; //将word转成char数组 char[]char

  • 1023: Pong’s Birds(概率)

    1023:Pong’sBirds 时间限制: 1Sec  内存限制: 128MB提交: 94  解决: 21[提交][状态][讨论版] 题目描述 Inordertotrainhisbirds,Pongisholdingacompetitionforthem.(Hehavebirds,doeshe?)Hehave2n birds,sohewanttoholdeliminationseries.Literally,ifn=2andhehas4birdsidentifiedas1,2,3,4,hewouldfirsthold competitionfor1and2,3and4,theonefailswouldbeeliminatedandthenheholdscompetitionforthewinners. Accordingtohislongobservation,foreachpairofbirdsheknowstheprobabilitytowinforeachbird,and

  • 1691:文章评分

    1691:文章评分时间限制:1000ms      内存限制:262144KB提交数:1094   通过数:175【题目描述】 nodgd的文章由$n$个小写英文字母组成。文章的一个子串指的是文章中的一段连续的字母,子串的长度就是这一段的字母个数。nodgd在文章中用了排比、对偶、前后照应之类的手法,所以就有很多个子串是相同或者相近的。为了向大家证明这是一篇好文章,nodgd决定给自己的文章进行评分。nodgd首先确定了一个整数$m$,然后统计出文章中有多少个不相同的长度为$m$的子串,这个数量就是文章的评分。 【输入】 第一行包含两个整数$n,m$,表示文章的长度和需要统计的子串长度。 第二行包含一个长度为$n$的只包含小写字母的字符串。 【输出】 一行一个整数,表示文章的评分。 【输入样例】 53 aaaab复制 【输出样例】 2复制 【提示】【样例解释1】 长度为$3$的子串有$3$个,分别是$aaa,aaa,aab$,其中不同的只有$2$个。 【输入样例2】 93 abcabacba复制

  • Maven配置文件配置指定JDK版本

    方法一:全局指定 settings.xml(第20行) 1<!--指定本地仓库位置--> 2<localRepository>D:\repository\</localRepository> 3 4<!--指定远程镜像--> 5<mirrors> 6<mirror> 7<id>central</id> 8<mirrorOf>central</mirrorOf> 9<name>aliyunmaven</name> 10<url>https://maven.aliyun.com/repository/central</url> 11</mirror> 12<mirror> 13<id>apache.snapshots.https</id> 14<mirrorOf>apache.snapshots.https</mirrorOf> 15<

  • node.js多进程 chirld_process cluster 子进程间通信 ipc原理分析对比

    node.js多进程chirld_processcluster子进程间通信ipc原理分析对比.pdf

  • Mac TouchBar 自定义工具-MTMR

    Github Install brewcaskinstallmtmr 复制 官网 lettheworldhavenohard-to-writecode^-^

  • ClickHouse介绍(四)ClickHouse使用操作

    ClickHouse使用操作 这章主要介绍在ClickHouse使用的各个操作的注意点。常规的统一语法不做详细介绍。   1.Join操作 在ClickHouse中,对连接操作定义了不同的精度,包含ALL、ANY和ASOF三种类型,默认为ALL。可以通过join_default_strictness配置修改默认精度(位于system.setting表中)。下面分别说明这3种精度。 首先建表并插入测试数据: --表join_tb1 CREATETABLEjoin_tb1 ( `id`String, `name`String, `time`DateTime ) ENGINE=MergeTree PARTITIONBYtoYYYYMM(time) ORDERBYid --表join_tb2 CREATETABLEjoin_tb2 ( `id`String, `rate`UInt8, `time`DateTime ) ENGINE=MergeTree PARTITIONBYtoYYYYMM(time) ORDERBYid --表join_tb3 CREATETABLEjoin_

  • SQL Server 和 Oracle 以及 MySQL 数据库

    推荐:https://www.zhihu.com/question/19866767 三者是目前市场占有率最高(依安装量而非收入)的关系数据库,而且很有代表性。排行第四的DB2(属IBM公司),与Oracle的定位和架构非常相似,就不赘述了。 如果要说明三者的区别,首先就要从历史入手。 Oracle 中文译作甲骨文,这是一家传奇的公司,有一个传奇的大老板LarryEllision。Ellision32岁还一事无成,读了三个大学,没得到一个学位文凭,换了十几家公司,老婆也离他而去。开始创业时只有1200美元,却使得Oracle公司连续12年销售额每年翻一番。 Oracle成立于1977年,早期的理论基础,反而来自于一篇IBM的论文《ARelationalModelofDataforLargeSharedDataBanks》【1】。作者CODD选取了关系代数的五种运算,并基于运算,架构了一种新型的数据存储模型。基于这种模型,Oracle成为了一个非常典型的关系数据库。因此也变的严谨、安全、高速、稳定,并且变的越来越庞大。 由于其诞生早、结构严谨、高可用、高性能等特点,使其在传统数据库应用中

  • hdu 3416 Marriage Match IV

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=3416 题意:starvae在城市A,要去城市B约妹子,要走最短路,并且每段路只能走一次,不能重复走。 题解:在走最短路的情况下,有多少条路从A到B,并且每条路是不重复的(路上经过的任何一条边都不可以重复)。首先是求最短路,然后根据所求的最短路找到这写最短路上的边,将这些边建图,求一次最大流。因为边只能走一次,所以每条边的容量是1,不用拆点(因为城市可以多次经过)。 代码: #include<stdio.h> #include<algorithm> #include<math.h> #include<string.h> #include<vector> #include<queue> #include<map> #include<stack> #include<iostream> #definepiacos(-1.0) #defineINF0x3f3f3f3f usingnamespac

  • Ubuntu上的MySQL可以远程访问

    1.3306端口是不是没有打开? 使用nestat命令查看3306端口状态: ~#netstat-an|grep3306复制 tcp       0     0127.0.0.1:3306         0.0.0.0:*              LISTEN 从结果可以看出3306端口只是在IP127.0.0.1上监听,所以拒绝了其他IP的访问。 解决方法:修改/etc/mysql/my.cnf文件。打开文件,找到下面内容: #Insteadofskip-networkingthedefaultisnowtolistenonlyon #localhostwhichismorecompatibleandisnotlesssecu

  • DM达梦数据库---执行计划查看

    查看执行计划explainforselect*fromt1whereid=1;level_id直接能标识出具体的执行的顺序,还是挺直观的。但操作符定义的比较另类,估计一时半会是记不住的。另外,表关联时被驱动表已经执行了SSEK2和BLKUP2,为啥还要执行CSCN2操作,不清楚这是为什么?感觉上不可理解。

  • webpack性能优化

    webpack性能优化

相关推荐

推荐阅读