天天看點

android jetpack hilt元件使用dagger參考代碼位址hilt相關的注解hilt基本使用Hilt進階使用

參考

https://developer.android.google.cn/training/dependency-injection/hilt-android

尤其要注意 studio4.2.1上是不能跑官網文檔中的hilt版本的

我使用的依賴版本配置

1、根gradle依賴

ext.kotlin_version = "1.5.0"//kotlin版本
ext.hilt_version = '2.35'//hilt版本
repositories {
    google()
    mavenCentral()
}
dependencies {
    classpath "com.android.tools.build:gradle:4.2.1"
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    classpath 'com.google.dagger:hilt-android-gradle-plugin:2.35'
}
           

2、app gradle依賴

implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
           

3、所使用的插件

id 'kotlin-kapt'
id 'kotlin-android-extensions'
           

代碼位址

https://github.com/ymeddmn/HiltDaggerDemo

official分支:抄的官網的demo

onlysampletest:最簡單的hilt使用

hilt相關的注解

@HiltAndroidApp:所有使用hilt的應用都需要使用這個注解,被使用在Application類上

@AndroidEntryPoint: Hilt可以為帶有

@AndroidEntryPoint

注釋的其他 Android 類提供依賴項,@AndroidEntryPoint可以被用在四大元件以及View上面

@Inject:擷取依賴

@HiltAndroidApp使用舉例

@HiltAndroidApp
class App: Application() {
​
    override fun onCreate() {
        super.onCreate()
    }
}
           

@AndroidEntryPoint和@Inject使用舉例

@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {
​
  @Inject
  AnalyticsAdapter analytics;
  ...
}
           

hilt基本使用

必須配置選項

Application中添加注解

@HiltAndroidApp
class App: Application() {
}
           

onlysampletest分支代碼詳解

這個分支實作的功能是在MainActivity中注入Car對象

1、首先加入必須配置選項

2、Car對象代碼:

class Car @Inject constructor() {
    fun drive(name: String) {
        println("老司機$name 線上開車")
    }
}
           
//Car的構造使用@Inject表示Car對象是一個可被注入的對象
           

3、MainActivity代碼:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
​
    @Inject
    lateinit var car: Car//Car對象使用@Inject注解,會自動被執行個體化,這裡必須使用lateinit延遲初始化才會有效
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        car.drive("mage")
    }
}
           

代碼運作後日志輸出:

2021-05-27 21:02:49.874 14104-14104/com.mage.hiltdaggerdemo I/System.out: 老司機mage 線上開車

complextest分支代碼詳解(更複雜一些的使用)

場景

onlysampletest分支中我們簡單的将Car注入到了MainActivity中,但是實際的業務場景我們面臨的業務肯定是遠比這個負責的,比如我們現在想給Car配置設定一個司機。正常情況下我們會建立一個Driver司機對象,然後再Car對象的構造函數中傳入Driver司機對象。

但是這明顯不是hilt所想要的

hilt的場景實作

下面說一下hilt的實作方式:

首先我們需要建立多個類

App Car Driver DriverImpl DriverModule MainActivity

Car的構造中會傳入Driver的實作,

Driver是司機的抽象實作,是一個接口。

DriverImple是Driver的實作類可以是任何一個具體的司機。

DriverModule負責提供Driver類的注入規則

下面是代碼展示:

1、添加必須配置選項

2、Car實作

class Car @Inject constructor(val driver: Driver) {//Car的構造函數中增加了Driver司機對象的實作
    fun drive() {
        println("老司機${driver.name} 線上開車")
    }
}
           

2、Driver司機接口

interface Driver {
    val name :String
}
           

3、DriverImple司機接口的實作

class DriverImpl @Inject constructor() : Driver {//因為DriverImpl需要被注入到Car的構造中,是以DriverImpl本身一個是被注入着,他的構造中也需要使用@Inject注解
    override val name: String
        get() = "mage"
}
           

4、DriverModule 配置Driver的注入規則

@Module//必須配置的注解,表示這個對象是Module的配置規則
@InstallIn(ActivityComponent::class)//表示這個module中的配置是用來注入到Activity中的
abstract class DriverModule {
    @Binds
    abstract fun bindDriver(driver: DriverImpl): Driver//形參中的DriverImple表示真實要注入Car構造方法中的Driver實作,傳回值Driver表示DriverImple所實作的抽象接口
}
           

5、MainActivity代碼

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
​
    @Inject
    lateinit var car: Car//這裡必須使用lateinit延遲初始化才會有效
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        car.drive()
    }
}
           

6、日志輸出

2021-05-27 21:30:43.462 18874-18874/com.mage.hiltdaggerdemo I/System.out: 老司機mage 線上開車

provider分支代碼

provider分支是對@Provides注解的解釋

complextest中我們使用@Binds注解将我們自定義的對象共享出去,那麼如果要共享的對象并非是我們自己建立的(例如OkhttpClient和Request)我們該如何處理呢,這個時候就可以使用@Provides了。代碼示例如下:

1、添加必須配置選項

2、建立OkhttpModule

@Module
@InstallIn(ActivityComponent::class)
object OkhttpModule {
    @Provides
    fun provideOkhttpClient(
        // Potential dependencies of this type
    ): OkHttpClient {
        return OkHttpClient()
    }
​
    @Provides
    fun providdeRequest():Request{
        return Request.Builder()
            .get()
            .url("https://developer.android.google.cn/training/dependency-injection/hilt-android")
            .build()
    }
}
           

3、MainActivity代碼

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
​
    @Inject
    lateinit var client: OkHttpClient
    @Inject
    lateinit var request: Request
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btn.setOnClickListener {
            client.newCall(request).enqueue(object :Callback{
                override fun onFailure(call: Call, e: IOException) {
                    println("請求失敗")
                }
                override fun onResponse(call: Call, response: Response) {
                    println("請求成功")
                }
            })
        }
    }
}
           

4、日志輸出

2021-05-28 07:36:25.477 14692-14775/com.mage.hiltdaggerdemo I/System.out: 請求成功

Hilt進階使用

multipleobjtest分支使用(同一類型提供多實作)

有些場景,同一類型的對象我們可能會提供多個執行個體,這個時候就需要特殊處理。舉例:

比如我們現在提供一個Car的接口抽象,然後同時給Car提供兩個接口實作TruckCar和TaxtCar。在MainActivity中代碼如下:

@Inject
lateinit var truck: Car
​
@Inject
lateinit var taxi: Car
           

因為注入的對象類型都是Car,是以編譯過程中就無法區分我們到底想注入TruckCar還是TaxtCar,是以編譯過程中代碼就好報錯。要解決這個問題就需要使用自定義注解,下面曬代碼:

1、必須配置選項

2、Car、TruckCar、TaxiCar代碼

interface Car {
    fun drive(name:String)
}
class TruckCar @Inject  constructor():Car{
    override fun drive(name: String) {
        println("$name 卡車老司機開車,嗚嗚")
    }
​
}
class TaxiCar @Inject  constructor():Car{
    override fun drive(name: String) {
        println("$name 計程車老司機開車,嗚嗚")
    }
​
}
           

3、CarModule代碼

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class Truck//卡車類注入标記
​
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class Taxi//計程車類注入标記
​
@Module
@InstallIn(ActivityComponent::class)
class CarModule {
​
    @Truck//卡車類生成規則加上這個注解,注入的時候也是用該注解編譯器就可以知道我們真實想注入的類型是TruckCar
    @Provides
    fun bindTruckCar(truckCar: TruckCar): Car {
        return TruckCar()
    }
​
    @Taxi//計程車類生成規則加上這個注解,注入的時候也是用該注解編譯器就可以知道我們真實想注入的類型是TaxiCar
    @Provides
    fun bindTaxtCar(taxiCar: TaxiCar): Car {
        return TaxiCar()
    }
}
           

4、日志輸出

2021-05-28 08:12:28.780 20418-20418/com.mage.hiltdaggerdemo I/System.out: mage 卡車老司機開車,嗚嗚 2021-05-28 08:12:28.780 20418-20418/com.mage.hiltdaggerdemo I/System.out: mage 計程車老司機開車,嗚嗚

預定義限定符(@ApplicationContext @ActivityContext)

抄一下官方的解釋,Hilt 提供了一些預定義的限定符。例如,由于您可能需要來自應用或 Activity 的

Context

類,是以 Hilt 提供了

@ApplicationContext

@ActivityContext

限定符。

代碼示例:

1、必須配置選項

2、BaseInfo類

class BaseInfo @Inject constructor(@ActivityContext private val context: Context) {
    fun printPackageName(){
        println("應用包名 ${context.packageName}")
    }
}
           

3、MainActivity類

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
​
    @Inject
    lateinit var baseInfo: BaseInfo
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btn.setOnClickListener {
            baseInfo.printPackageName()
        }
    }
}
           

4、日志輸出

2021-05-28 08:20:56.292 21928-21928/com.mage.hiltdaggerdemo I/System.out: 應用包名 com.mage.hiltdaggerdemo

官方提供的類生成元件(抄官方)

對于您可以從中執行字段注入的每個 Android 類,都有一個關聯的 Hilt 元件,您可以在

@InstallIn

注釋中引用該元件。每個 Hilt 元件負責将其綁定注入相應的 Android 類。

所有元件如下,元件的生命周期和是依賴于注入元件類的生命周期的

ApplicationComponent

Application

ActivityRetainedComponent

ViewModel

作用于ViewModel

ActivityComponent

Activity

FragmentComponent

Fragment

ViewComponent

View

ViewWithFragmentComponent

帶有

@WithFragmentBindings

注釋的

View

ServiceComponent

Service

元件作用域(抄官方)

預設情況下,Hilt 中的所有綁定都未限定作用域。這意味着,每當應用請求綁定時,Hilt 都會建立所需類型的一個新執行個體。

不過,Hilt 也允許将綁定的作用域限定為特定元件。Hilt 隻為綁定作用域限定到的元件的每個執行個體建立一次限定作用域的綁定,對該綁定的所有請求共享同一執行個體。

比如當元件作用域為@Singleton的時候,這個元件就是一個全局單例的

比如當元件作用域為@ActivityScoped的時候,這個元件在同一個Activity内都是同一個對象執行個體

是以預設的元件和作用域

Android 類 生成的元件 作用域

Application

ApplicationComponent

@Singleton

View Model

ActivityRetainedComponent

@ActivityRetainedScope

Activity

ActivityComponent

@ActivityScoped

Fragment

FragmentComponent

@FragmentScoped

View

ViewComponent

@ViewScoped

帶有

@WithFragmentBindings

注釋的

View

ViewWithFragmentComponent

@ViewScoped

Service

ServiceComponent

@ServiceScoped

元件預設綁定(抄官方)

Android 元件 預設綁定

ApplicationComponent

Application

ActivityRetainedComponent

Application

ActivityComponent

Application

Activity

FragmentComponent

Application

Activity

Fragment

ViewComponent

Application

Activity

View

ViewWithFragmentComponent

Application

Activity

Fragment

View

ServiceComponent

Application

Service