Kotlin Dagger2

首先:進行運行環(huán)境的配置
step1:
導(dǎo)入build.grable閉包配置
在需要使用Dagger2模塊的build.grable文件內(nèi)添加(運行環(huán)境和jar包)
implementation "com.google.dagger:dagger:2.20"
kapt "com.google.dagger:dagger-compiler:2.20"
step2:
在使用模塊的build.gradle 內(nèi)添加
apply plugin: 'kotlin-kapt'
主要內(nèi)容
依賴注入:
在當(dāng)前類運行時當(dāng)前對象與某個對象發(fā)生依賴關(guān)系,把這種依賴在一個合適的時候注入“運行時”,也就是依賴注入,在沒調(diào)用時不與其他對象發(fā)生依賴關(guān)系,在運行調(diào)用時就與其他對象發(fā)生依賴關(guān)系。

? @inject 和 @component : 注解 和 組件
? @Module 和 @Provides :在module 內(nèi)有一個 Provides
? @Scope 和 @Singleton :作用域(使用范圍) 和 使用單例模式
? @Qualifier 和 @Named :限定符
使用Dagger2 依賴注入

@Inject:
也就是注入想要使用的對象實例,注意這里注入的時實例,所以使用注入不需要實例化對象。
使用 @Inject 注解,可以不需要實例化帶有依賴注入注解 @Inject 的對象。使用時需要加入lateinit關(guān)鍵字,這樣可以在不調(diào)用時不占用多余的內(nèi)存空間。
@Inject時對應(yīng)出現(xiàn)的,被依賴對象要使用@Inject 依賴對象也要使用@Inject。
@Component:注入器,連接目標(biāo)類和依賴類的橋梁
@Component注解的必須時接口或者抽象類。Component依賴關(guān)系是通過dependencies屬性添加。
App必須有一個Component用來管理全局實例
簡單說就是,可以通過Component訪問到Module中提供的依賴注入對象。假設(shè),如果有兩個Module,AModule、BModule,如果Component只注冊了AModule,而沒有注冊BModule,那么BModule中提供的對象,無法進行依賴注入!

@Module:
@Module用來解決的問題
1.使用第三方庫的時候,如果第三方庫沒有使用dagger2 的@Inject并且第三方庫無法修改其中的內(nèi)容,那么也就無法使用@Inject注解了
2.接口不能實例化,只能通過實現(xiàn)類實例化。
@Module的使用
Module是一個簡單工廠,是用來床創(chuàng)建類實例的方法,比如第三方庫中的類無法修改,但是還是要使用@Inject注解的化,那么就可以把想要注解的對象的實例化過程提取到Module工廠里,這樣就不怕無法使用@Inject標(biāo)記實例化而無法使用@Inject注解
@Component 可以通過modules屬性加入多個module,這樣就可以得到多個實例化工廠中的對象。
@provides:
? @provides是在Module中使用的,Module是一個提供具體實例化對象的工廠,那么@provides就是Module中用來標(biāo)注創(chuàng)建實例的方法。

實例化流程
? Component搜索@Inject注解的屬性
? Component查找Module中以@Provides注解的對應(yīng)方法,創(chuàng)建實例
Inject 和 Module 維度
? (一種是直接使用@Inject標(biāo)記被實現(xiàn)對象和實現(xiàn)對象來實例化)
? (一種是使用Module在Module里使用@Provides注解來實例化具體的對象)
注意:
如果@Inject 和 Module 兩種創(chuàng)建方式都存在的化,那么Module的優(yōu)先級會高@Inject
? 比如先去找Module中有沒有實現(xiàn)這個對象,如果沒有的話再去@Inject中找對象

具體使用:
第一種:直接使用@Inject注解標(biāo)注需要實現(xiàn)的屬性對象
第一步:在引用屬性加上 @Inject注解
如:這是屬性 mPresenter:T 加上@Inject注解
open class BaseMvpActivity<T: BasePresenter<out BaseView>> :BaseActivity(),BaseView {
override fun showLoading() {
}

override fun hideLoading() {
}

override fun onError() {
}
// 創(chuàng)建一個BasePresenter的引用
@Inject
lateinit var mPresenter: T

}
第二步:被@Inject標(biāo)注的具體類型對象需要在構(gòu)造函數(shù)加上@Inject標(biāo)注
因為類的引用屬性有被@Inject標(biāo)注,既然標(biāo)注了就需要實現(xiàn)當(dāng)前引用屬性的具體類,使用就需要在具體類的構(gòu)造方法加上@Inject標(biāo)注,如果當(dāng)前的引用用來實例化多個類,那么那幾個有被實現(xiàn)的類都需要在構(gòu)造方法前加上@Inject (如:@Inject constructor())
如:RegisterPresenter是一個具體的實現(xiàn)類,它實現(xiàn)了@Inject標(biāo)注的引用屬性的類
class RegisterPresenter @Inject constructor(): BasePresenter<RegisterView>(){
// 這里由于使用了Dagger2 的@Inject注解所以當(dāng)前類可以使用@Inject注解引用的實例對象
@Inject
lateinit var userService: UserService
fun register(mobile: String, verifyCode: String, pwd: String){
/*
業(yè)務(wù)邏輯
如:請求網(wǎng)絡(luò),做注冊,將最后的結(jié)果返回給Activity
*/
// val userService = UserServiceImpl()
// register 就是一個被被監(jiān)聽者
userService.register(mobile,verifyCode,pwd)
.execute(object : BaseResoureSubscriber<Boolean>(){
override fun onNext(t: Boolean) {
mView.onRegisterResult(t)
}
})
}

fun login(mobile: String,pwd: String){
    /*
        業(yè)務(wù)邏輯
        如:請求網(wǎng)絡(luò),做注冊,將最后的結(jié)果返回給Activity
     */
    val userService = UserServiceImpl()
    // register 就是一個被被監(jiān)聽者
    userService.register(mobile,"",pwd)
            .execute(object : BaseResoureSubscriber<Boolean>(){
                override fun onNext(t: Boolean) {
                    mView.onRegisterResult(t)
                }
            })
}

}

第二種,使用Module來實現(xiàn)接口的實現(xiàn)類
第一步,實現(xiàn)Module工廠類
@Module
class UserModule {
/**
* @param service 通過@Provides 標(biāo)注之后,Dagger2就會使用遞歸的形式
* 去查找當(dāng)前被標(biāo)注方法的參數(shù)列表的具體類是否有被@Inject標(biāo)注
* 如果參數(shù)列表中的具體實現(xiàn)類有被@Inject標(biāo)注,
* 那么就將當(dāng)前參數(shù)名稱的屬性實例化使屬性帶有具體的實現(xiàn),
* 也就是實例化的對象。
*
* @return 它的返回類型是當(dāng)前參數(shù)列表中具體類實現(xiàn)的接口類型
*/
@Provides
fun providesUserService(service: UserServiceImpl): UserService{
return service
}

}
第二步,使用@Inject標(biāo)注Module工廠中想要使用@Provides實現(xiàn)的接口實現(xiàn)類
如:UsrServiceImpl是一個實現(xiàn)了UsrService接口的類
class UserServiceImpl @Inject constructor() : UserService {
// 在具體的類 UserRepository的構(gòu)造方法加上標(biāo)注 @Inject,
// 那么這里只要使用@Inject標(biāo)注一個延遲實例化的屬性,
// 只要當(dāng)前被@Inject標(biāo)注的屬性有被調(diào)用到,那么@Inject
// 就會自動找到當(dāng)前標(biāo)注的屬性的具體類,通過具體類去實現(xiàn)當(dāng)前的
// 屬性對象。
@Inject
lateinit var repository: UserRepository
override fun register(mobile: String, verifyCode: String, pwd: String): Flowable<Boolean> {
// val repository = UserRepository()
return Flowable.create({ it.onNext(true) }, BackpressureStrategy.BUFFER)

}

}
第三步,使用@Inject lateinit 延遲加載在調(diào)用時通過Module工廠自動實例化類
@Inject
lateinit var userService: UserService

第四步,使用Component標(biāo)注把Module中得到的實例注入到具體的類中,這樣被注入的實例才可以使用Module中的實例。
// 要注入的Module
@Component(modules = arrayOf(UserModule::class))
interface UserComponent {
// component 需要注入的地方,也就是主調(diào)用的地方
fun inject(activity:RegisterActivity)
}

第五步,使用內(nèi)部創(chuàng)建的Compoent對象注入依賴,具體看以下代碼。

與當(dāng)前對象依賴的有Register
class RegisterActivity : BaseMvpActivity<RegisterPresenter>(),RegisterView {
override fun onRegisterResult(result: Boolean) {
toast("注冊成功").show()
}

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

// mPresenter = RegisterPresenter()
// mPresenter.mView = this
initInjection()
mRegisterBtn.setOnClickListener {
mPresenter.register(mMobileEt.text.toString(),mVerifyCodeEt.text.toString(),mPwdEt.text.toString())
}
}

private fun initInjection() {
    /*
            注入Module,通過builder得到Builder的引用,userModule用來檢查UserModule時否為空,
        通過build得到UserModule的對象,最后通過inject將當(dāng)前位置的對象注入到Component,創(chuàng)建于當(dāng)前對象有依賴的所有對象。

比如以上使用mPresenter.register調(diào)用了UserService的實現(xiàn)方法,就等于register
方法得到了UserService接口的注入。
*/
DaggerUserComponent.builder().userModule(UserModule()).build().inject(this)
mPresenter.mView = this
}
}

@Scope
? @Conpe主要用于Component的組織方式,(也就是用來標(biāo)注Component的作用域級別)
? 管理COmponent和Module之間的匹配關(guān)系
? 提高可讀性,見名知意
@Singleton
? @Scope是一個接口,@Singleton是實現(xiàn)@Scope的一個子類
? @Singleton 是@Scope的一種默認(rèn)實現(xiàn)
? @Singleton并沒有實現(xiàn)單例的能力
? ApplicationComponent單例是由代碼控制實現(xiàn)的

@Scope的使用
以Component組織方式自定義Scope

自定義Scope與Dagger2的配置流程總結(jié):
說明:@Singleton 的具體作用是在創(chuàng)建 Component進行module注入的時候,
如果@Component是被@Singleton標(biāo)注的,
// 比如,AppComponent可以注入的是由被@Singleton標(biāo)注的module工廠
@Singleton
// @component是被@Singleton標(biāo)注的,所以只能注入module中被@Singleton標(biāo)注的工廠方法的實例
@Component(modules = arrayOf(AppModule::class))
那么@Component(module = arrayof(module:: class)),
這里的module工廠的工廠方法也必須是被@Singleton標(biāo)注的
@Module
class AppModule(private val context: BaseApplication) {
// @Singleton 標(biāo)注的后就可以使后臺知道Component可以傳入的是哪個module
@Singleton
// module 創(chuàng)建所有與BaseApplication由所依賴并且由加@Inject標(biāo)注的實例對象
@Provides
fun providesActivity(): Context {
return context
}
}
自定義Scope 如果想要由多個@Singleton 來標(biāo)注多個作用域,也就是多個模塊那么就可以自己自定義一個@Singleton
一個ActivityScope
@Scope
@Documented
@Retention(RUNTIME)
annotation class ActivityScope
用自定義@Scope來標(biāo)注module工廠方法
@Module
class ActivityModule(private val activity: Activity) {
// module 創(chuàng)建所有與BaseApplication由所依賴并且由加@Inject標(biāo)注的實例對象
@Provides
fun providesContext(): Activity {
return activity
}
}

注意:@Singleton在標(biāo)注module時,必須標(biāo)注在工廠方法,不可標(biāo)注在整個module類,并且如果@Singleton標(biāo)注的時某個高層父類,那么其他module中的工廠方法如果有實現(xiàn)了這個高層父類,就不可用其他標(biāo)注標(biāo)注這個工廠方法
總結(jié):dagger2 在查找創(chuàng)建對象的過程
step1: 創(chuàng)建一個module
找module中是否有創(chuàng)建該對象的工廠(這也就是為什么module用來處理第三方框架不能使用dagger2 的原因了,因為它可以讓我們自己添加創(chuàng)建對象的工廠而不是
通過@Inject標(biāo)注具體對象的構(gòu)造方法后在其他地方使用@Injec標(biāo)注有被@Inject標(biāo)注的實例就可以使用dagger2創(chuàng)建實例而不用我們自己去創(chuàng)建實例)
step2:創(chuàng)建一個component注入
component注入是用于那些可以方便修改本地代碼的場景,而第三方無法修改代碼就只能用module
compenent的使用是通過將具體的類文件注入到使用的地方,那些有被@inject標(biāo)的對象或者module持有對象工廠的對象都將得到創(chuàng)建,在使用這些對象的時候?qū)⒉恍枰@示的創(chuàng)建對象。
step3:在被注入的地方或者想要使用注入對象的地方進行操作
被注入的地方使用代碼
DaggerUserComponent.builder().userModule(UserModule()).build().inject(this)
;這段代碼用來創(chuàng)建傳入當(dāng)前實例到module進行創(chuàng)建實例
;具體的執(zhí)行流程
dagger2默認(rèn)生成 DaggerUserCompent這里的UserCompent就是使用@Component標(biāo)注進行注入對象的文件模板。
再用builder() 來得到Builder()的引用,Builder()內(nèi)就存在一個userModule用來檢查傳入的UserModule() 對象是否為空,不為空則使用build()來得到DaggerUserComponent() 對象, 使用對象中的inject()接口方法傳入當(dāng)前對象到 UserComponent進行注入對象
最后,在當(dāng)前類內(nèi)部就可以使用module工廠內(nèi)的對象

@Qualifier
注解迷失:同一個接口有多個實現(xiàn)鱷類,編譯報錯,分不清使用哪一個實現(xiàn)類
使用限定符分
@Named
Qualifier的一種實現(xiàn)方式
以名稱區(qū)分使用的那種注解實現(xiàn)
自定義Qualifier
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
annotation.class.ActivityQualifier

使用:比如一個module里有兩個返回同樣接口類型的工廠方法,那么在使用@Inject注解調(diào)用實現(xiàn)對象的時候,后臺機制將不知道如何選擇調(diào)用哪個工廠方法來實例化類,
這里使用了@Named() 括號內(nèi)標(biāo)注的就相當(dāng)于一個用來區(qū)分工廠方法的標(biāo)識符,第一個工廠方法在括號內(nèi)使用的表示名不和第二個標(biāo)識符的一樣,在使用@Inject來標(biāo)注本地實現(xiàn)的引用對象時,要想知道具體時實例化哪一個對象,就得加上@Named(),括號內(nèi)的區(qū)分字符串來區(qū)分實例化的對象

定義
/**

  • @創(chuàng)建者 xia
  • @創(chuàng)建時間 2018/12/27 21:11
  • @描述 一個用于創(chuàng)建接口實現(xiàn)類實例對象的工廠
    /
    @Module
    class UserModule {
    /
    *
    • @param service 通過@Provides 標(biāo)注之后,Dagger2就會使用遞歸的形式
    • 去查找當(dāng)前被標(biāo)注方法的參數(shù)列表的具體類是否有被@Inject標(biāo)注
    • 如果參數(shù)列表中的具體實現(xiàn)類有被@Inject標(biāo)注,
    • 那么就將當(dāng)前參數(shù)名稱的屬性實例化使屬性帶有具體的實現(xiàn),
    • 也就是實例化的對象。
    • @return 它的返回類型是當(dāng)前參數(shù)列表中具體類實現(xiàn)的接口類型
      */
      @Named("service")
      @Provides
      fun providesUserService(service: UserServiceImpl): UserService{
      return service
      }
      @Named("service2")
      @Provides
      fun providesUserService2(service: UserServiceImpl2): UserService{
      return service
      }
      }

使用
class RegisterPresenter @Inject constructor(): BasePresenter<RegisterView>(){
/*
使用@Inject標(biāo)注屬性讓Module工廠來實現(xiàn)具體的接口實現(xiàn)類,
因為接口中有使用@Provider標(biāo)注實現(xiàn)了 UserService接口的類
/
@Inject
// 域變量
@field:[Named("service")]
lateinit var userService: UserService
@Inject
@field:[Named("service2")]
lateinit var userService2: UserService
fun register(mobile: String, verifyCode: String, pwd: String){
/

業(yè)務(wù)邏輯
如:請求網(wǎng)絡(luò),做注冊,將最后的結(jié)果返回給Activity
*/
// val userService = UserServiceImpl()
// register 就是一個被被監(jiān)聽者
userService.register(mobile,verifyCode,pwd)
.execute(object : BaseResoureSubscriber<Boolean>(){
override fun onNext(t: Boolean) {
mView.onRegisterResult(t)
}
})
}

fun register2(mobile: String, verifyCode: String, pwd: String){
    /*
        業(yè)務(wù)邏輯
        如:請求網(wǎng)絡(luò),做注冊,將最后的結(jié)果返回給Activity
     */

// val userService = UserServiceImpl()
// register 就是一個被被監(jiān)聽者
userService2.register(mobile,verifyCode,pwd)
.execute(object : BaseResoureSubscriber<Boolean>(){
override fun onNext(t: Boolean) {
mView.onRegisterResult(t)
}
})
}

fun login(mobile: String,pwd: String){
    /*
        業(yè)務(wù)邏輯
        如:請求網(wǎng)絡(luò),做注冊,將最后的結(jié)果返回給Activity
     */
    val userService = UserServiceImpl()
    // register 就是一個被被監(jiān)聽者
    userService.register(mobile,"",pwd)
            .execute(object : BaseResoureSubscriber<Boolean>(){
                override fun onNext(t: Boolean) {
                    mView.onRegisterResult(t)
                }
            })
}

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容