欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

kotlin使用Dagger2的過程全紀(jì)錄

 更新時(shí)間:2018年03月14日 09:16:47   作者:風(fēng)少俠  
Dagger2是一款基于Java注解,在編譯階段完成依賴注入的開源庫,主要用于模塊間解耦,方便進(jìn)行測試。下面這篇文章主要給大家介紹了關(guān)于kotlin使用Dagger2的過程的相關(guān)資料,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。

前言

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

Dagger2有Google接手開發(fā)的一個(gè)基于JSR-330標(biāo)準(zhǔn)的依賴注入框架,它會在編譯期間自動生成相關(guān)代碼,負(fù)責(zé)依賴對象的創(chuàng)建,達(dá)到解耦目的。

下面將詳細(xì)介紹關(guān)于kotlin使用Dagger2的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細(xì)的介紹吧。

kotlin中配置Dagger2

在app模塊的build.gradle文件中進(jìn)行如下配置,關(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è)注解本身并沒有作用,它需要依賴于注入框架才具有意義,可以用來標(biāo)記構(gòu)造函數(shù)、屬性和方法。

標(biāo)記構(gòu)造函數(shù)

被標(biāo)記的構(gòu)造函數(shù)可以有0個(gè)或多個(gè)依賴作為參數(shù)。

同一個(gè)類中最多只可以標(biāo)記一個(gè)構(gòu)造函數(shù)。

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

注意在kotlin中這種寫法是不被允許的,因?yàn)檫@等價(jià)于java中的多個(gè)構(gòu)造方法People(String name), People() 正確的寫法應(yīng)該是這樣:

data class People constructor(val name: String) {
 @Inject
 constructor() : this("Tom")
}

標(biāo)記屬性

被標(biāo)記的屬性不能是final的,kotlin中不能是val。

被注入進(jìn)的屬性不能用private修飾(是Dagger2不支持,而非@Inject不支持)。

 @Inject
 lateinit var people:People

標(biāo)記方法

被標(biāo)記的方法可以有0個(gè)或多個(gè)依賴作為參數(shù)。

方法不能是抽象的。

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

這種方法注入和屬性注入并沒有什么本質(zhì)上的不同,實(shí)現(xiàn)效果也基本一樣。還有一種做法是@Inject標(biāo)記被注入類的某個(gè)方法,該方法會在類的構(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())
 }
}

運(yùn)行結(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

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

Members-injection methods:

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

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

等價(jià)于:

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

Provision methods:

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

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

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

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

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

第二步:編寫一個(gè)注射器接口

@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)//會在這句代碼時(shí)執(zhí)行注入的操作
  people.hello()
 }
}

03-01 14:30:23.425 3256-3256/? I/System.out: hello
//大功告成

當(dāng)然,上面這種只是最簡單的用法,如果需要傳入一些非自定義類的實(shí)例就不適用了,畢竟你不能在第三方的類中加入@Inject注解。此時(shí)就需要用到@Module和@Provides注解。

@Module

用來標(biāo)記類,為Component提供依賴,相當(dāng)于告訴Component,如果需要依賴可以來找我,當(dāng)然前提是在Component中配置了該Module。同時(shí)Module可以通過includes依賴其他的Module。

@Provides

用來標(biāo)記Module中的方法,該方法的返回類型是你需要提供的依賴類型。

舉個(gè)自己項(xiàng)目中的例子,我需要在presenter中創(chuàng)建一個(gè)pl2303對象,pl2303對象的創(chuàng)建又需要context和pl2303Interface,所以我們需要提供三個(gè)依賴,因?yàn)閏ontext在其他地方也要用,我們單獨(dú)提出來:

@Module
class ContextModule(private var mContext: Context) {
 @Provides
 fun getContext() = mContext
}

pl2303Interface只有這一個(gè)地方要用:

@Module(includes = arrayOf(ContextModule::class))
class Pl2303Module(private var pl2303Interface: ActivityCallBridge.PL2303Interface) {
 @Provides
 fun providePl2303(mContext: Context): Pl2303 {
  return Pl2303(mContext, pl2303Interface)
 }
}

其中includes可以是多個(gè),我們這里把ContextModule加進(jìn)來,這樣創(chuàng)建pl2303就只差一個(gè)pl2303Interface,這是個(gè)接口對象,不能new,從構(gòu)造函數(shù)注入進(jìn)來。接下來創(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)
 }
}

如果在大型項(xiàng)目中,一個(gè)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的一個(gè)實(shí)現(xiàn)。有時(shí)候我們會需要提供幾個(gè)相同類型的依賴(比如繼承于同一父類),如果不做處理的話編譯器就不知道我們需要的具體是哪一個(gè)依賴而報(bào)錯(cuò),比如這樣:

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)

這時(shí)候就需要標(biāo)記一下來告訴編譯器我們需要的是哪個(gè)依賴:

@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的一個(gè)實(shí)現(xiàn)而已,所以我們也可以用@Qualifier來達(dá)到一樣的效果,實(shí)際使用中也更推薦使用@Qualifier的方式,因?yàn)锧Named需要手寫字符串來進(jìn)行標(biāo)識,容易出錯(cuò)。

使用@Qualifier需要注意:

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

我們可以看一下@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)測試依然是可以運(yùn)行的。

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

@Scope是用來管理依賴的生命周期的。它和@Qualifier一樣是用來自定義注解的,而@Singleton和@Named類似,是@Scope的默認(rèn)實(shí)現(xiàn)。

如果一個(gè)注射器和創(chuàng)建依賴對象的地方?jīng)]有標(biāo)記@Scope,那么每次注入時(shí)都會創(chuàng)建一個(gè)新的對象,如果標(biāo)記了@Scope,則在規(guī)定的生命周期內(nèi)會使用同一個(gè)對象,特別注意是在規(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}")
 }
}

運(yùn)行結(jié)果:

people===people_2:false

說明確實(shí)是兩個(gè)不同的對象,接下來我們改造一下:

@Singleton
data class People constructor(val name: String) {
 ...//和之前一樣
}

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

再次看下運(yùn)行結(jié)果:

people===people_2:true

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

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • Android OnCreate()中獲取控件高度與寬度兩種方法詳解

    Android OnCreate()中獲取控件高度與寬度兩種方法詳解

    這篇文章主要介紹了Android OnCreate()中獲取控件高度與寬度兩種方法詳解的相關(guān)資料,這里提供了兩種方法,大家可以都看下,需要的朋友可以參考下
    2016-12-12
  • Android短信驗(yàn)證碼自動填寫實(shí)現(xiàn)代碼

    Android短信驗(yàn)證碼自動填寫實(shí)現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了Android短信驗(yàn)證碼自動填寫實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • Android仿ios加載loading菊花圖效果

    Android仿ios加載loading菊花圖效果

    這篇文章主要介紹了Android仿ios加載loading菊花圖效果,本文通過實(shí)例代碼效果圖展示給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-09-09
  • 詳解Android中Notification的使用方法

    詳解Android中Notification的使用方法

    這篇文章主要介紹了Android中Notification的使用方法,最典型的應(yīng)用就是未看短信和未接來電的顯示,還有QQ微信,想要深入了解Notification的朋友可以參考本文
    2015-12-12
  • Android FTP服務(wù)器上傳文件攻略(代碼詳解)

    Android FTP服務(wù)器上傳文件攻略(代碼詳解)

    這篇文章主要介紹了Android FTP服務(wù)器上傳文件攻略,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • JNI方法實(shí)現(xiàn)圖片壓縮(壓縮率極高)

    JNI方法實(shí)現(xiàn)圖片壓縮(壓縮率極高)

    這篇文章主要給大家介紹了一種JNI方法實(shí)現(xiàn)圖片壓縮(壓縮率極高)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • 基于Android RxCache使用方法詳解

    基于Android RxCache使用方法詳解

    下面小編就為大家分享一篇基于Android RxCache使用方法詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • Android使用元數(shù)據(jù)實(shí)現(xiàn)配置信息的傳遞方法詳細(xì)介紹

    Android使用元數(shù)據(jù)實(shí)現(xiàn)配置信息的傳遞方法詳細(xì)介紹

    這篇文章主要介紹了Android使用元數(shù)據(jù)實(shí)現(xiàn)配置信息的傳遞方法,也就是實(shí)現(xiàn)配置快捷菜單功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-09-09
  • Android多個(gè)TAB選項(xiàng)卡切換效果

    Android多個(gè)TAB選項(xiàng)卡切換效果

    這篇文章主要介紹了Android多個(gè)TAB選項(xiàng)卡切換效果的實(shí)現(xiàn)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-04-04
  • 基于startActivityForResult方法處理兩個(gè)Activity之間數(shù)據(jù)傳遞問題

    基于startActivityForResult方法處理兩個(gè)Activity之間數(shù)據(jù)傳遞問題

    這篇文章主要介紹了基于startActivityForResult方法處理兩個(gè)Activity之間數(shù)據(jù)傳遞問題的相關(guān)資料,需要的朋友可以參考下
    2015-11-11

最新評論