亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

kotlin使用Dagger2的過程全紀錄

2024-07-21 23:03:43
字體:
來源:轉載
供稿:網友

前言

Dagger2作為依賴注入神器,相信很多朋友都聽說過它的大名。只不過它的有些概念,理解起來并不是那么清晰,并且在使用的過程中,也比較迷糊。

Dagger2有Google接手開發的一個基于JSR-330標準的依賴注入框架,它會在編譯期間自動生成相關代碼,負責依賴對象的創建,達到解耦目的。

下面將詳細介紹關于kotlin/281154.html">kotlin使用Dagger2的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。

kotlin中配置Dagger2

在app模塊的build.gradle文件中進行如下配置,關于kapt的相關知識。

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'}

相關常用注解:

  • @Inject
  • @Component
  • @Module
  • @Provides
  • @Qualifier和@Named
  • @Scope和@Singleton

@Inject

@Inject注解只是JSR-330中定義的注解,在javax.inject包中。 這個注解本身并沒有作用,它需要依賴于注入框架才具有意義,可以用來標記構造函數、屬性和方法。

標記構造函數

被標記的構造函數可以有0個或多個依賴作為參數。

同一個類中最多只可以標記一個構造函數。

class People @Inject constructor(val name:String = "Tom")

注意在kotlin中這種寫法是不被允許的,因為這等價于java中的多個構造方法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個或多個依賴作為參數。

方法不能是抽象的。

class HomeActivity : AppCompatActivity() { private lateinit var people:People @Inject fun setPeople(people:People){ this.people = people }}

這種方法注入和屬性注入并沒有什么本質上的不同,實現效果也基本一樣。還有一種做法是@Inject標記被注入類的某個方法,該方法會在類的構造方法之后接著被調用:

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) //執行相關注入操作 ... println(people.toString()) }}

運行結果是這樣的:

01-02 11:57:30.995 16601-16601/? I/System.out: init:Tom01-02 11:57:30.995 16601-16601/? I/System.out: hello:Tom01-02 11:57:30.995 16601-16601/? I/System.out: People(name=Tom)

@Component

可以理解為一個注射器,可以算是Dagger2中最核心的一個注解,用來標記一個接口或者抽象類。使用@Component標記的接口,會在編譯時自動生成一個Dagger+類名的實現類實現依賴注入。在Component中一般可以定義兩種方法:

Members-injection methods:

該方法有一個參數,表示需要注入到的類,提醒Dagger在該類中尋找需要被注入的屬性(被@Inject標記)。

void inject(SomeType someType);//無返回值SomeType injectAndReturn(SomeType someType);//返回它的參數類型

等價于:

MembersInjector<SomeType> getMembersInjector();//使用MembersInjector.injectMembers方法注入

Provision methods:

該方法沒有參數,返回一個需要被注入(或被提供)的依賴。一般用于為其他Component提供依賴的時候。

SomeType getSomeType();Provider<SomeType> getSomeTypeProvider();//可以通過Provider.get訪問任意次Lazy<SomeType> getLazySomeType();//通過Lazy.get第一次訪問時創建實例,并在之后的訪問中都訪問同一個實例
@Componentinterface HomeComponent { fun inject(activity: HomeActivity) fun injectAndReturn(activity: HomeActivity): HomeActivity fun getInjectors(): MembersInjector<HomeActivity>  fun getPeople():People}

事實上,了解到這里我們已經可以使用最簡單的Dagger2用法,畢竟有了依賴和注射器,只需要注入就可以了,我們來看一個最簡單的Dagger2實例,只使用@Inject和@Component來完成注入。

第一步:在需要被注入的類的構造方法上添加注解@Inject

class People @Inject constructor() { fun hello(){  println("hello") }}

第二步:編寫一個注射器接口

@Componentinterface 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)//會在這句代碼時執行注入的操作  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中創建一個pl2303對象,pl2303對象的創建又需要context和pl2303Interface,所以我們需要提供三個依賴,因為context在其他地方也要用,我們單獨提出來:

@Moduleclass 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加進來,這樣創建pl2303就只差一個pl2303Interface,這是個接口對象,不能new,從構造函數注入進來。接下來創建注射器:

@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,那么不需要傳入參數的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的一個實現。有時候我們會需要提供幾個相同類型的依賴(比如繼承于同一父類),如果不做處理的話編譯器就不知道我們需要的具體是哪一個依賴而報錯,比如這樣:

abstract class Animalclass Dog : Animal() { override fun toString(): String {  return "dog" }}class Cat : Animal() { override fun toString(): String {  return "cat" }}@Moduleclass AnimalModule { @Provides fun provideDog(): Animal = Dog() @Provides fun provideCat(): Animal = Cat()}data class Pet @Inject constructor(val pet: Animal)

這時候就需要標記一下來告訴編譯器我們需要的是哪個依賴:

@Moduleclass 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的一個實現而已,所以我們也可以用@Qualifier來達到一樣的效果,實際使用中也更推薦使用@Qualifier的方式,因為@Named需要手寫字符串來進行標識,容易出錯。

使用@Qualifier需要注意:

  • 創建一個自定義的Qualifier至少需要@Qualifier, @Retention(RUNTIME)這兩個注解。
  • 可以有自己的屬性。

我們可以看一下@Named的源碼來加深一下理解:

@Qualifier@Documented@Retention(RUNTIME)public @interface Named { /** The name. */ String value() default "";}

下面我們比葫蘆畫瓢來改造一下上面的例子:

@Moduleclass 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 CatAnimdata class Pet @Inject constructor(@CatAnim val pet: Animal)

經測試依然是可以運行的。

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是用來標記包含可注入構造函數的類或者提供注入依賴對象的類,簡單來說,可以用來標記包含@Inject構造函數的類或者@Module類。

@Scope是用來管理依賴的生命周期的。它和@Qualifier一樣是用來自定義注解的,而@Singleton和@Named類似,是@Scope的默認實現。

如果一個注射器和創建依賴對象的地方沒有標記@Scope,那么每次注入時都會創建一個新的對象,如果標記了@Scope,則在規定的生命周期內會使用同一個對象,特別注意是在規定的生命周期內單例,并不是全局單例,或者可以理解為在@Component內單例。

還是借助上面的例子:

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}") }}

運行結果:

people===people_2:false

說明確實是兩個不同的對象,接下來我們改造一下:

@Singletondata class People constructor(val name: String) { ...//和之前一樣}@Singleton@Component(modules = arrayOf(AnimalModule::class))interface HomeComponent { fun inject(activity: HomeActivity)}...//HomeActivity代碼和之前一樣

再次看下運行結果:

people===people_2:true

說明這次兩次都是訪問的同一個對象。上面提到這只是一個局部單例,那么怎么實現一個全局單例呢,很簡單,只要保證標記的Component在全局只初始化一次即可,比如在Application中初始化,篇幅限制代碼就不貼了,有興趣的騷年可以自己實踐一下。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到kotlin教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲欧美日韩在线高清直播| 欧美激情视频网| 91精品国产91久久久久久最新| 国产一区红桃视频| 中文字幕亚洲精品| 欧美老女人性生活| 亚洲**2019国产| 91精品久久久久久久久久| 国产精品久久久久久久天堂| 亚洲区中文字幕| 亚洲最大的免费| 国产精品视频精品| 久久久久久久国产精品视频| 欧美精品一区二区三区国产精品| 国产精品吹潮在线观看| 欧美理论片在线观看| 精品香蕉在线观看视频一| 欧美一级片免费在线| 免费99精品国产自在在线| 欧美日韩精品在线视频| 宅男66日本亚洲欧美视频| 日韩国产精品视频| 国产精品三级久久久久久电影| 自拍亚洲一区欧美另类| 成人在线激情视频| 亚洲网址你懂得| 亚洲欧美一区二区三区情侣bbw| 成人一区二区电影| 欧美裸体男粗大视频在线观看| 久久精品电影一区二区| 日韩精品在线免费播放| 欧美裸体xxxx极品少妇软件| 亚洲国产精品网站| 国产日韩欧美夫妻视频在线观看| 欧美伦理91i| 97热精品视频官网| 精品在线小视频| 国产精品色婷婷视频| 亚洲福利视频网站| 久久久久久久久久久91| 亚洲欧美综合图区| 久久午夜a级毛片| 国产精品免费在线免费| 久久久精品在线观看| 国产精品视频导航| 国产精品久久一区主播| 欧美性猛xxx| 在线播放国产一区二区三区| 亚洲男人av电影| 欧美在线视频一二三| 欧美富婆性猛交| 色综合伊人色综合网| 日韩欧美中文字幕在线播放| 国产日韩亚洲欧美| 成人免费网站在线观看| 欧美激情一区二区三区在线视频观看| 国产精品亚洲第一区| 日本精品免费观看| 亚洲欧美成人在线| 国产精品久久久久久久一区探花| 亚洲精品在线看| 97视频免费在线看| 亚洲欧美综合精品久久成人| 欧美老妇交乱视频| 国产欧美精品日韩精品| 日本道色综合久久影院| 日韩欧美国产骚| 久久久久久久久久久91| 黑人巨大精品欧美一区免费视频| 日本成熟性欧美| 亚洲视频国产视频| 日韩av快播网址| 国产欧美一区二区三区久久| 亚洲欧美国内爽妇网| 一本色道久久88精品综合| 亚洲黄色在线观看| 亚州精品天堂中文字幕| 亚洲精品视频在线观看视频| 在线a欧美视频| 国产精品无码专区在线观看| 成人网址在线观看| 国产伦精品免费视频| 国内揄拍国内精品少妇国语| 色综合久久久久久中文网| 日韩精品免费电影| 欧美大码xxxx| 亚洲女人天堂视频| 免费91麻豆精品国产自产在线观看| 在线视频国产日韩| 国内精品久久久久| 国产亚洲精品综合一区91| 韩剧1988免费观看全集| 亚洲自拍小视频免费观看| 精品亚洲国产视频| 亚洲自拍小视频| 久久综合色88| 91最新在线免费观看| 国产亚洲激情视频在线| 亚洲男人天堂视频| 亚洲国产另类 国产精品国产免费| 欧美一级黑人aaaaaaa做受| 欧美激情欧美狂野欧美精品| 国产亚洲激情视频在线| 亚洲国产福利在线| 成人激情视频在线播放| 精品国产精品三级精品av网址| 欧美精品第一页在线播放| 亚洲女同精品视频| 国产精品日韩欧美| 国产精品美女久久| 日韩电影中文 亚洲精品乱码| 亚洲欧美日韩成人| 亚洲人成77777在线观看网| 欧美午夜精品伦理| 青青精品视频播放| 免费91麻豆精品国产自产在线观看| 蜜臀久久99精品久久久无需会员| 亚洲加勒比久久88色综合| 北条麻妃在线一区二区| 欧美视频在线观看 亚洲欧| 久久久久久久久久久久av| 欧美壮男野外gaytube| 狠狠爱在线视频一区| 久久视频在线视频| 国产不卡av在线免费观看| 亚洲免费影视第一页| 欧美精品免费播放| 91探花福利精品国产自产在线| 国产综合久久久久| 高清亚洲成在人网站天堂| 韩国日本不卡在线| 国产精品视频播放| 麻豆一区二区在线观看| 国产精品99一区| 欧美精品在线免费播放| 成人免费自拍视频| 日韩国产欧美区| 国产精品久久久久久av| 91精品久久久久久久久久久| 美女撒尿一区二区三区| 欧美成人精品在线| 色777狠狠综合秋免鲁丝| 亚洲a在线播放| 日本中文字幕不卡免费| 中文国产亚洲喷潮| 亚洲精品国产成人| 精品性高朝久久久久久久| 久国内精品在线| 日韩有码在线观看| 国产精品久久久久久久久久ktv| 另类图片亚洲另类| 久久久成人的性感天堂| 欧美电影《睫毛膏》| 日韩av在线影视| 久久久久久91香蕉国产| 久久精品国产亚洲精品2020| 91久久精品久久国产性色也91| 91福利视频网| 18性欧美xxxⅹ性满足| 在线观看国产精品日韩av| 久久久精品2019中文字幕神马| 国产精品99久久久久久久久久久久| 欧美日韩视频在线| 国产精品色婷婷视频|