Dagger2之Kotlin寫法

依賴

項目的gradleapi

buildscript {
ext.dagger_version = '2.11'
}
複製代碼

module的gradlebash

//多模塊項目,這個必須在使用到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"
}
複製代碼

概念

@Inject

  1. 修飾構造方法
  2. 修飾變量,在宿主類裏,引入要注入的實例

@Module

生產實例的工廠,每個實例都是經過@Provides修飾的方法提供的app

專門解決,不是本身寫的類沒法在其構造函數上加@Inject的狀況框架

固然本身寫的類也能夠經過@Provides修飾的方法提供,這樣就不會找@Inject的構造函數了ide

Component

Component是橋樑紐帶,是一個接口函數

功能1:組織依賴關係(鏈條)gradle

一個Component能夠組織多個Module 一個Component還能夠組織引入其餘的Componentui

依賴的查找順序爲:先找@Module,若是找到了就中止,若是找不到就去找@Injectthis

功能2:爲宿主類提供Inject方法google

@Inject+@Component

全部實例類型所有在我掌控之中 最簡單的狀況 (不須要Module)

(要注入的實例的類都是本身寫的,不須要Module,本身寫的類本身用@inject修飾構造方法)

構造方法不帶參數

  1. 注入類的構造方法使用 @Inject
class Apple @Inject constructor(){
    var color:String ="red"
}
複製代碼
  1. 必須有一個FruitComponent接口,提供一個注入方法

    注意:參數必須爲要使用對象注入的類

@Component
interface FruitComponent {
    fun inject(activity: MainActivity)
}
複製代碼
  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)

    }
}
複製代碼

構造方法帶參數

(可是所帶參數的構造函數,也能夠被@Inject修飾,即所帶參數的類型的類也是本身寫的)

class Apple @Inject constructor(val knife: Knife) {
    var color: String = "red"
}
複製代碼
class Knife @Inject constructor() {
    var name: String = "小刀"
}
複製代碼
@Component
interface FruitComponent {
    fun inject(activity: MainActivity)
}
複製代碼
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)

    }
}
複製代碼

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

有些實例類型,我沒法掌控

別慌!@Module來幫忙

兩種狀況

  1. 你要注入的實例的類型就不是你本身寫的類,沒法使用@inject
  2. 你要注入的實例的類型就是你本身寫的類,可是帶了一個參數,這個參數類型的類不是你本身寫的,沒法使用@inject

狀況一

@Module
class SecondModule {
    @Provides
    fun provideString():String{
        return  "我是String,你能在個人構造方法上加@inject嗎?是的,你不能!"
    }
}
複製代碼
@Component(modules = [SecondModule::class])
interface SecondComponent {
    fun  inject(activity:MainActivity)
}
複製代碼
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)
    }
}

複製代碼

狀況二

Person 是我本身寫的類,我能夠在它構造方法上面加@inject,可是他有一個參數是String,你要提供Person對象就必須提供Person所須要的全部參數,咱們沒法在String上加@inject

class Person @Inject constructor(var name: String){
    
}
複製代碼
@Module
class SecondModule {
    @Provides
    fun provideString():String{
        return  "我是爲Person提供name的,可是我是String,你能在個人構造方法上加@inject嗎?是的,你不能!"
    }
}
複製代碼
@Component(modules = [SecondModule::class])
interface SecondComponent {
    fun  inject(activity:MainActivity)
}
複製代碼
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)
    }
}
複製代碼

SecondComponet依賴其餘的ThirdComponet

1.先準備第一個ThirdComponet,他一會要被SecondComponet依賴

class Cat @Inject constructor(var age: Int)
複製代碼
@Module
class ThirdMoudle {
//    這裏直接提供了Cat的實例,而不是隻是提供一個age(相似上面Person的name)
//    直接提供實例,就不用寫提供age實例的provides方法了
    @Provides
    fun provideCat():Cat{
        return Cat(1)
    }
}
複製代碼
<!--好多坑,看註釋-->
@Component(modules = [ThirdMoudle::class])
interface ThirdComponet {
//    ★由於這個ThirdComponet要被SceondComponent依賴,這裏必須提供一個方法,否則報錯
//    ★若是沒有Componet依賴ThirdComponet,這裏能夠不寫
    fun provideCat():Cat
    //fun inject(activity:Activity)
    //★若是ThirdComponet沒有要注入的類,這裏不要寫inject也行,可是寫的話千萬不能同SecondComponet所注入的類同樣,會報錯
}
複製代碼

2. 看第二個SecondComponent的寫法

class Person @Inject constructor(var name: String)
複製代碼
@Module
class SecondModule {
    @Provides
    fun provideString():String{
        return  "我是爲Person提供name的, 可是我是String,你能在個人構造方法上加@inject嗎?是的,你不能!"
    }
}
複製代碼
@Component(modules = [SecondModule::class]
    ,dependencies = [ThirdComponet::class])
    //★dependencies依賴ThirdComponet
interface SecondComponent {
    fun  inject(activity:MainActivity)
}
複製代碼

3. 注入到MainActivity使用

class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var person: Person
    @Inject
    lateinit var cat: Cat

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

        val thirdComponet = DaggerThirdComponet.builder().build()

        DaggerSecondComponent.builder()
            .thirdComponet(thirdComponet)//★注意這裏傳入thirdComponet
            .build().inject(this)
        tv1.setOnClickListener {
            rx1()
        }
    }

    private fun rx1() {
        Log.e("CCC", person.name)
        Log.e("CCC", "${cat.age}")
    }
}
複製代碼

Scope

摘抄自:Dagger2:Scope, Component間依賴和subComponent

參考

Android:dagger2讓你愛不釋手-基礎依賴注入框架篇

Dagger2:Scope, Component間依賴和subComponent

相關文章
相關標籤/搜索