首發(fā)于公眾號(hào): DSGtalk1989
最可怕的還是來了,依賴注入一直是一般工程師最最不愿意去碰的東西。復(fù)雜,不易理解。但是不得不承認(rèn),使用起來真的很方便。本章節(jié)將不盡量不涉及原理說明,只介紹依賴注入使用。
相比較而言,可能知道Dagger的人會(huì)多很多。但是這里選擇用Kodein作為kotlin項(xiàng)目的依賴注入框架,除了kodein本身是用kotlin寫的之外,還有他更加容易理解的使用方式,我們多說無益,跟著我來一起上手吧!
第一步,添加依賴
// 基礎(chǔ)組件
implementation 'org.kodein.di:kodein-di-generic-jvm:6.1.0'
// Android擴(kuò)展組件
implementation 'org.kodein.di:kodein-di-framework-android-core:6.1.0'
// support擴(kuò)展組件,我的項(xiàng)目中用到了v4包的Fragment,因此我需要它
implementation 'org.kodein.di:kodein-di-framework-android-support:6.1.0'
第二步,在主application中添加實(shí)現(xiàn)KodeinAware接口
class FrameApplication : Application(), KodeinAware {
override val kodein: Kodein = Kodein.lazy { }
}
實(shí)現(xiàn)之后會(huì)要求你必須復(fù)寫kodein屬性,我們直接定義成延遲屬性lazy,具體見委托。我們需要在lazy中做一些初始化的工作,其實(shí)顯而易見了,就是我們將要注入的依賴。
第三步,定義Module
我們挑一個(gè)最最常用的注入例子,Retrofit的service注入。這里建議大家把所有需要注入的通用module,放在同一個(gè)地方,比如ModuleFactory.kt
kodein針對(duì)module的語法如下
val moduleName = Kodein.Module(MODULE_TAG) {
bind<injectClass>() with singleton { init it }
instance<haveInjectedClass>
.haveInjectedClassFun(instance())
}
不知道直接這么寫,大家可否理解。首先module是一個(gè)屬性或者方法都可以,指向的Kodein.Module需要傳入一個(gè)TAG字符串,然后我們將需要注入的對(duì)象類型綁定,并在singleton后面的lambda表達(dá)式中對(duì)注入對(duì)象進(jìn)行初始化。
針對(duì)已經(jīng)聲明過注入的類型對(duì)象,我們直接可以使用instance帶注入類型的方式當(dāng)成注入對(duì)象來使用,并且在相關(guān)方法中一旦需要傳入已經(jīng)注入過的對(duì)象,直接調(diào)用instance()即可,框架會(huì)幫我們找到相應(yīng)的對(duì)象。
所以這邊okHttpModule的注入如下:
/**
* OKHTTP module
*/
val httpClientModule = Kodein.Module(HTTP_CLIENT_MODULE_TAG) {
bind<Retrofit.Builder>() with singleton { Retrofit.Builder() }
bind<OkHttpClient.Builder>() with singleton { OkHttpClient.Builder() }
bind<Retrofit>() with singleton {
instance<Retrofit.Builder>()
.baseUrl(AppConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(instance())
.build()
}
bind<OkHttpClient>() with singleton {
//打印請(qǐng)求log
val logging = HttpLoggingInterceptor()
logging.level = if (BuildConfig.DEBUG) {
HttpLoggingInterceptor.Level.BODY
} else {
HttpLoggingInterceptor.Level.NONE
}
instance<OkHttpClient.Builder>()
.addInterceptor(logging)
.addInterceptor(headerInterceptor())
.build()
}
}
第四步,import module
在application中,直接做import
override val kodein: Kodein = Kodein.lazy {
import(androidCoreModule(this@FrameApplication))
import(androidXModule(this@FrameApplication))
import(httpClientModule)
}
這里我們還引入了androidCoreModule和androidXModule,相關(guān)核心控件的context,甚至很多的系統(tǒng)服務(wù)。
第五步,使用注入
在Activity中,我們同樣需要實(shí)現(xiàn)KodeinAware接口,并且復(fù)寫屬性kodein
override val kodein by org.kodein.di.android.kodein()
Ok,就這么簡(jiǎn)單。接下去所有需要使用到注入的都是同樣的操作。
val serviceManager: ServiceManager by instance()
val userDao: UserDao by instance()
所有的屬性,我們都只要指出他是什么類型,同時(shí)委托給instance()即可,框架會(huì)幫我們自動(dòng)的初始化。
BTW,有同學(xué)跟我反應(yīng),有個(gè)注入框架比上面講的kodein還好用,叫做koin,大家可以也看一下哦,之后抽空我來做橫向比較。有個(gè)框架很好用,有空就訪問這個(gè)鏈接koin
