Dagger2之Kotlin写法

2020-11-22 20:53:43

Dagger2之Kotlin写法

依赖

项目的gradle

buildscript {
ext.dagger_version = '2.11'
}123

module的gradle

//多模块项目,这个必须在使用到dagger2的所有moudle里都配置
apply plugin: 'kotlin-kapt'

dependencies {
    //dagger2,这个可以写在BaseMoudle里
    api "com.google.dagger:dagger:$dagger_version"
    //多模块项目,这个必须在使用到dagger2的所有moudle里都配置
    kapt "com.google.dagger:dagger-compiler:$dagger_version"
}123456789

概念

@Inject

  1. 修饰构造方法

  2. 修饰变量,在宿主类里,引入要注入的实例

@Module

生产实例的工厂,每一个实例都是通过@Provides修饰的方法提供的

专门解决,不是自己写的类无法在其构造函数上加@Inject的情况

当然自己写的类也可以通过@Provides修饰的方法提供,这样就不会找@Inject的构造函数了

Component

Component是桥梁纽带,是一个接口

功能1:组织依赖关系(链条)

一个Component可以组织多个Module
一个Component还可以组织引入其他的Component

依赖的查找顺序为:先找@Module,如果找到了就停止,如果找不到就去找@Inject

功能2:为宿主类提供Inject方法

@Inject+@Component

所有实例类型全部在我掌控之中
最简单的情况 (不需要Module)

(要注入的实例的类都是自己写的,不需要Module,自己写的类自己用@inject修饰构造方法)

构造方法不带参数

  1. 注入类的构造方法使用 @Inject

class Apple @Inject constructor(){
    var color:String ="red"
}123
  1. 必须有一个FruitComponent接口,提供一个注入方法

    注意:参数必须为要使用对象注入的类

@Component
interface FruitComponent {
    fun inject(activity: MainActivity)
}1234
  1. 通过inject注入所有对象,@Inject使用注入对象

class MainActivity : AppCompatActivity() {
    @Inject
    lateinit var apple: Apple//注入实例

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        DaggerFruitComponent.builder().build().inject(this)//必须注入一下
        tv1.setOnClickListener {
            rx1()
        }
    }

    private fun rx1() {
        toast(apple.color)

    }
}12345678910111213141516171819

构造方法带参数

(但是所带参数的构造函数,也可以被@Inject修饰,即所带参数的类型的类也是自己写的)

class Apple @Inject constructor(val knife: Knife) {
    var color: String = "red"
}123
class Knife @Inject constructor() {
    var name: String = "小刀"
}123
@Component
interface FruitComponent {
    fun inject(activity: MainActivity)
}1234
class MainActivity : AppCompatActivity() {
    @Inject
    lateinit var apple: Apple
    @Inject
    lateinit var knife: Knife
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        DaggerFruitComponent.builder().build().inject(this)
        tv1.setOnClickListener {
            rx1()
        }
    }

    private fun rx1() {
        Log.e("CCC",knife.name)
        Log.e("CCC",apple.color)

    }
}123456789101112131415161718192021

@Inject+@Component+@Module(含@Provides)

有些实例类型,我无法掌控

别慌!@Module来帮忙

两种情况

  1. 你要注入的实例的类型就不是你自己写的类,无法使用@inject

  2. 你要注入的实例的类型就是你自己写的类,但是带了一个参数,这个参数类型的类不是你自己写的,无法使用@inject

情况一

@Module
class SecondModule {
    @Provides
    fun provideString():String{
        return  "我是String,你能在我的构造方法上加@inject吗?是的,你不能!"
    }
}1234567
@Component(modules = [SecondModule::class])
interface SecondComponent {
    fun  inject(activity:MainActivity)
}1234
class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var s: String


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        DaggerSecondComponent.builder().build().inject(this)//注入
        tv1.setOnClickListener {
            rx1()
        }
    }

    private fun rx1() {
        Log.e("CCC", s)
    }
}123456789101112131415161718192021

情况二

Person 是我自己写的类,我可以在它构造方法上面加@inject,但是他有一个参数是String,你要提供Person对象就必须提供Person所需要的所有参数,我们无法在String上加@inject

class Person @Inject constructor(var name: String){
    
}123
@Module
class SecondModule {
    @Provides
    fun provideString():String{
        return  "我是为Person提供name的,但是我是String,你能在我的构造方法上加@inject吗?是的,你不能!"
    }
}1234567
@Component(modules = [SecondModule::class])
interface SecondComponent {
    fun  inject(activity:MainActivity)
}1234
class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var person: Person

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        DaggerSecondComponent.builder().build().inject(this)
        tv1.setOnClickListener {
            rx1()
        }
    }

    private fun rx1() {
        Log.e("CCC", person.name)
    }
}


  • 2020-12-06 20:38:30

    intellij idea远程开发remote

    开发时一般的平台都是windows,但windows对开发极其不友好,一般都会在本地开启虚拟机,安装上linux环境进行项目的部署测试。下面介绍一种windows主机与linux虚拟机代码同步的方法。这个工具适用于jerbrains公司旗下的很多产品,比如idea、webstrom、phpstrom等。但是要注意你安装的IDE必须是专业版的,社区版的IDE是没有这个代码同步功能的哦!

  • 2020-12-07 05:46:56

    npm设置和取消代理的方法

    有时候是设置了全局代理对npm并不生效,不如直接给npm设置代理,至少在mac电脑我是有这种感觉的。

  • 2020-12-07 15:04:03

    node开发邮件系统总结

    因为multipart这种形式比较复杂,因此要利用boundary分割符,将邮件体分割成不同段来进行解析,boundary分为父段和子段,父段一般出现0次或1次,出现在末尾,每个子段中也有content-type和boundary,需要在进行解析,如果遇到i,iii里面的情况可直接解析,如果遇到ii中的情况,再按ii中的步骤进行解析

  • 2020-12-07 15:17:45

    email-templates + mjml 发送邮件

    mjml 是一个很不错的响应式邮件html 内容标签库,email-templates 是一个灵活强大的邮件发送框架,两者集成起来我们 可以设计灵活强大的邮件发送系统,以下是一个简单的集成使用,实际使用还有好多地方需要完善

  • 2020-12-07 15:19:00

    响应式邮件的编写插件介绍mjml

    以前做项目碰到发邮件的需求,邮件模板的编辑就是一件头疼的事。因为虽说邮件是支持 HTML 的,但是确是 HTML 子集程度的支持,所以存在必须通过 <table> 排版的恶心之处,还有很多兼容性的坑。本质上是各家邮件商的标准有差异吧。

  • 2020-12-07 16:14:22

    nodejs队列实现amqplib,rabbitmq

    其中StartConsumer 会在项目启动时启动,在整个生命周期中一直保持监听状态,在程序结束时mq的链接关闭。需要注意的是 noAck 这个参数,当为false是表示消息出队后不会自动删除,如果设置成true,则无论消息处理成功与否此消息会被删除。注意到在消息不成功是,调用了ch.nack(msg)),此方法是将消息重新入队。

  • 2020-12-07 16:15:46

    RabbitMQ详解

    当前市面上mq的产品很多,比如RabbitMQ、Kafka、ActiveMQ、ZeroMQ和阿里巴巴捐献给Apache的RocketMQ。甚至连redis这种NoSQL都支持MQ的功能。 ActiveMQ ActiveMQ是apache出品,最流行的,能力强劲的开源消息总线,并且它一个完全支持JMS规范的消息中间件。其丰富的API、多种集群构建模式使得它成为业界老牌消息中间件,在中小型企业中应用广泛。

  • 2020-12-07 16:17:53

    nodejs用redis实现队列操作

    其实nodejs实现队列的方式又很多中,也有很多开源的插件和队列数据库可以使用,但是呢,如果我们一个简单的项目,完全可以使用redis来实现队列, 这样再不增加技术难度的同事,我们也就可以完美的实现一个队列