本篇文章給大家分享的是有關(guān)如何在kotlin中使用Dagger2,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
創(chuàng)新互聯(lián)是一家朝氣蓬勃的網(wǎng)站建設(shè)公司。公司專注于為企業(yè)提供信息化建設(shè)解決方案。從事網(wǎng)站開發(fā),網(wǎng)站制作,網(wǎng)站設(shè)計,網(wǎng)站模板,微信公眾號開發(fā),軟件開發(fā),微信平臺小程序開發(fā),10余年建站對石涼亭等多個領(lǐng)域,擁有多年建站經(jīng)驗。
kotlin中配置Dagger2
在app模塊的build.gradle文件中進行如下配置,關(guān)于kapt的相關(guān)知識。
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' android { ... } dependencies { ... implementation 'com.google.dagger:dagger:2.11' kapt 'com.google.dagger:dagger-compiler:2.11' }
相關(guān)常用注解:
@Inject
@Component
@Module
@Provides
@Qualifier和@Named
@Scope和@Singleton
@Inject
@Inject注解只是JSR-330中定義的注解,在javax.inject包中。 這個注解本身并沒有作用,它需要依賴于注入框架才具有意義,可以用來標記構(gòu)造函數(shù)、屬性和方法。
標記構(gòu)造函數(shù)
被標記的構(gòu)造函數(shù)可以有0個或多個依賴作為參數(shù)。
同一個類中最多只可以標記一個構(gòu)造函數(shù)。
class People @Inject constructor(val name:String = "Tom")
注意在kotlin中這種寫法是不被允許的,因為這等價于java中的多個構(gòu)造方法People(String name), People()
正確的寫法應該是這樣:
data class People constructor(val name: String) { @Inject constructor() : this("Tom") }
標記屬性
被標記的屬性不能是final的,kotlin中不能是val。
被注入進的屬性不能用private修飾(是Dagger2不支持,而非@Inject不支持)。
@Inject lateinit var people:People
標記方法
被標記的方法可以有0個或多個依賴作為參數(shù)。
方法不能是抽象的。
class HomeActivity : AppCompatActivity() { private lateinit var people:People @Inject fun setPeople(people:People){ this.people = people } }
這種方法注入和屬性注入并沒有什么本質(zhì)上的不同,實現(xiàn)效果也基本一樣。還有一種做法是@Inject標記被注入類的某個方法,該方法會在類的構(gòu)造方法之后接著被調(diào)用:
data class People constructor(val name: String) { @Inject constructor() : this("Tom") init { println("init:$name") } @Inject fun hello(){ println("hello:$name") } } class HomeActivity : AppCompatActivity() { @Inject lateinit var people:People override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_home) //執(zhí)行相關(guān)注入操作 ... println(people.toString()) } }
運行結(jié)果是這樣的:
01-02 11:57:30.995 16601-16601/? I/System.out: init:Tom 01-02 11:57:30.995 16601-16601/? I/System.out: hello:Tom 01-02 11:57:30.995 16601-16601/? I/System.out: People(name=Tom)
@Component
可以理解為一個注射器,可以算是Dagger2中最核心的一個注解,用來標記一個接口或者抽象類。使用@Component標記的接口,會在編譯時自動生成一個Dagger+類名的實現(xiàn)類實現(xiàn)依賴注入。在Component中一般可以定義兩種方法:
Members-injection methods:
該方法有一個參數(shù),表示需要注入到的類,提醒Dagger在該類中尋找需要被注入的屬性(被@Inject標記)。
void inject(SomeType someType);//無返回值 SomeType injectAndReturn(SomeType someType);//返回它的參數(shù)類型
等價于:
MembersInjector<SomeType> getMembersInjector();//使用MembersInjector.injectMembers方法注入
Provision methods:
該方法沒有參數(shù),返回一個需要被注入(或被提供)的依賴。一般用于為其他Component提供依賴的時候。
SomeType getSomeType(); Provider<SomeType> getSomeTypeProvider();//可以通過Provider.get訪問任意次 Lazy<SomeType> getLazySomeType();//通過Lazy.get第一次訪問時創(chuàng)建實例,并在之后的訪問中都訪問同一個實例
@Component interface HomeComponent { fun inject(activity: HomeActivity) fun injectAndReturn(activity: HomeActivity): HomeActivity fun getInjectors(): MembersInjector<HomeActivity> fun getPeople():People }
事實上,了解到這里我們已經(jīng)可以使用最簡單的Dagger2用法,畢竟有了依賴和注射器,只需要注入就可以了,我們來看一個最簡單的Dagger2實例,只使用@Inject和@Component來完成注入。
第一步:在需要被注入的類的構(gòu)造方法上添加注解@Inject
class People @Inject constructor() { fun hello(){ println("hello") } }
第二步:編寫一個注射器接口
@Component interface HomeComponent { fun inject(activity: HomeActivity) }
第三步:注入
class HomeActivity : AppCompatActivity() { @Inject lateinit var people:People override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_home) DaggerHomeComponent.builder() .build() .inject(this)//會在這句代碼時執(zhí)行注入的操作 people.hello() } } 03-01 14:30:23.425 3256-3256/? I/System.out: hello //大功告成
當然,上面這種只是最簡單的用法,如果需要傳入一些非自定義類的實例就不適用了,畢竟你不能在第三方的類中加入@Inject注解。此時就需要用到@Module和@Provides注解。
@Module
用來標記類,為Component提供依賴,相當于告訴Component,如果需要依賴可以來找我,當然前提是在Component中配置了該Module。同時Module可以通過includes依賴其他的Module。
@Provides
用來標記Module中的方法,該方法的返回類型是你需要提供的依賴類型。
舉個自己項目中的例子,我需要在presenter中創(chuàng)建一個pl2303對象,pl2303對象的創(chuàng)建又需要context和pl2303Interface,所以我們需要提供三個依賴,因為context在其他地方也要用,我們單獨提出來:
@Module class ContextModule(private var mContext: Context) { @Provides fun getContext() = mContext }
pl2303Interface只有這一個地方要用:
@Module(includes = arrayOf(ContextModule::class)) class Pl2303Module(private var pl2303Interface: ActivityCallBridge.PL2303Interface) { @Provides fun providePl2303(mContext: Context): Pl2303 { return Pl2303(mContext, pl2303Interface) } }
其中includes可以是多個,我們這里把ContextModule加進來,這樣創(chuàng)建pl2303就只差一個pl2303Interface,這是個接口對象,不能new,從構(gòu)造函數(shù)注入進來。接下來創(chuàng)建注射器:
@Component(modules = arrayOf(Pl2303Module::class)) interface MainPresenterComponent { fun inject(presenter: MainPresenter) }
最后注入:
class MainPresenter(val view: MainContract.View) : MainContract.Presenter, ActivityCallBridge.PL2303Interface, LifecycleObserver { @Inject lateinit var pl2303: Pl2303 init { DaggerMainPresenterComponent.builder() .contextModule(ContextModule(view.context)) .pl2303Module(Pl2303Module(this)) .build() .inject(this) } }
如果在大型項目中,一個Component有很多的Module,那么不需要傳入?yún)?shù)的Module是可以省略的,看一下官方的注釋文檔:
public static void main(String[] args) { OtherComponent otherComponent = ...; MyComponent component = DaggerMyComponent.builder() // required because component dependencies must be set(必須的) .otherComponent(otherComponent) // required because FlagsModule has constructor parameters(必須的) .flagsModule(new FlagsModule(args)) // may be elided because a no-args constructor is visible(可以省略的) .myApplicationModule(new MyApplicationModule()) .build(); }
@Named和@Qualifier
@Named是@Qualifier的一個實現(xiàn)。有時候我們會需要提供幾個相同類型的依賴(比如繼承于同一父類),如果不做處理的話編譯器就不知道我們需要的具體是哪一個依賴而報錯,比如這樣:
abstract class Animal class Dog : Animal() { override fun toString(): String { return "dog" } } class Cat : Animal() { override fun toString(): String { return "cat" } } @Module class AnimalModule { @Provides fun provideDog(): Animal = Dog() @Provides fun provideCat(): Animal = Cat() } data class Pet @Inject constructor(val pet: Animal)
這時候就需要標記一下來告訴編譯器我們需要的是哪個依賴:
@Module class AnimalModule { @Provides @Named("dog") fun provideDog(): Animal = Dog() @Provides @Named("cat") fun provideCat(): Animal = Cat() } data class Pet @Inject constructor(@Named("dog") val pet: Animal)
上面我們說了@Named只是@Qualifier的一個實現(xiàn)而已,所以我們也可以用@Qualifier來達到一樣的效果,實際使用中也更推薦使用@Qualifier的方式,因為@Named需要手寫字符串來進行標識,容易出錯。
使用@Qualifier需要注意:
創(chuàng)建一個自定義的Qualifier至少需要@Qualifier, @Retention(RUNTIME)這兩個注解。
可以有自己的屬性。
我們可以看一下@Named的源碼來加深一下理解:
@Qualifier @Documented @Retention(RUNTIME) public @interface Named { /** The name. */ String value() default ""; }
下面我們比葫蘆畫瓢來改造一下上面的例子:
@Module class AnimalModule { @Provides @DogAnim fun provideDog(): Animal = Dog() @Provides @CatAnim fun provideCat(): Animal = Cat() } @Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class DogAnim @Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class CatAnim data class Pet @Inject constructor(@CatAnim val pet: Animal)
經(jīng)測試依然是可以運行的。
Pet(pet=cat)
@Scope和@Singleton
A scope annotation applies to a class containing an injectable constructor and governs how the injector reuses instances of the type
@Scope是用來標記包含可注入構(gòu)造函數(shù)的類或者提供注入依賴對象的類,簡單來說,可以用來標記包含@Inject構(gòu)造函數(shù)的類或者@Module類。
@Scope是用來管理依賴的生命周期的。它和@Qualifier一樣是用來自定義注解的,而@Singleton和@Named類似,是@Scope的默認實現(xiàn)。
如果一個注射器和創(chuàng)建依賴對象的地方?jīng)]有標記@Scope,那么每次注入時都會創(chuàng)建一個新的對象,如果標記了@Scope,則在規(guī)定的生命周期內(nèi)會使用同一個對象,特別注意是在規(guī)定的生命周期內(nèi)單例,并不是全局單例,或者可以理解為在@Component內(nèi)單例。
還是借助上面的例子:
data class People constructor(val name: String) { @Inject constructor() : this("Tom") init { println("init:$name") } @Inject fun hello(){ println("hello:$name") } } class HomeActivity : AppCompatActivity() { @Inject lateinit var people: People @Inject lateinit var people_2: People override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_home) DaggerHomeComponent.builder() .build() .inject(this) println("people===people_2:${people===people_2}") } }
運行結(jié)果:
people===people_2:false
說明確實是兩個不同的對象,接下來我們改造一下:
@Singleton data class People constructor(val name: String) { ...//和之前一樣 } @Singleton @Component(modules = arrayOf(AnimalModule::class)) interface HomeComponent { fun inject(activity: HomeActivity) } ...//HomeActivity代碼和之前一樣
再次看下運行結(jié)果:
people===people_2:true
以上就是如何在kotlin中使用Dagger2,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降摹OM隳芡ㄟ^這篇文章學到更多知識。更多詳情敬請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
名稱欄目:如何在kotlin中使用Dagger2
網(wǎng)站地址:http://www.rwnh.cn/article0/peopio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、App設(shè)計、商城網(wǎng)站、建站公司、企業(yè)建站、網(wǎng)站排名
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)