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

Android中Hilt的使用詳解

 更新時間:2023年06月14日 11:23:56   作者:縱馬天下  
Hilt?是?Android?的依賴項(xiàng)注入庫,可減少在項(xiàng)目中執(zhí)行手動依賴項(xiàng)注入的樣板代碼,本文就來為大家介紹一下Hilt的具體使用吧,希望對大家有所幫助

Hilt 是 Android 的依賴項(xiàng)注入庫,可減少在項(xiàng)目中執(zhí)行手動依賴項(xiàng)注入的樣板代碼。執(zhí)行手動依賴項(xiàng)注入要求您手動構(gòu)造每個類及其依賴項(xiàng),并借助容器重復(fù)使用和管理依賴項(xiàng)。

Hilt 通過為項(xiàng)目中的每個 Android 類提供容器并自動管理其生命周期,提供了一種在應(yīng)用中使用 DI(依賴項(xiàng)注入)的標(biāo)準(zhǔn)方法。Hilt 在熱門 DI 庫 Dagger 的基礎(chǔ)上構(gòu)建而成,因而能夠受益于 Dagger 的編譯時正確性、運(yùn)行時性能、可伸縮性和 Android Studio 支持。本篇只探討其使用方式,其步驟如下

在項(xiàng)目中引入Hilt

在project/build.gradle下加入kotlin和hilt的插件

buildscript {
    ext.kotlin_version = '1.5.31'
    ext.hilt_version = '2.40'
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:7.0.3'
        //kotlin編譯插件
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        //hilt編譯插件
        classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
    }
}

在app/build.gradle下加入kotlin和hilt

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-parcelize'
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'
}
android {
    compileSdkVersion 31
    buildToolsVersion "30.0.3"
    defaultConfig {
        applicationId "com.example.android.hilt"
        minSdkVersion 16
        targetSdkVersion 31
        versionCode 1
        versionName "1.0"
        javaCompileOptions {
            annotationProcessorOptions {
                arguments["room.incremental"] = "true"
            }
        }
    }
    compileOptions {
        sourceCompatibility 1.8
        targetCompatibility 1.8
    }
}
dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
    // Room
    implementation "androidx.room:room-runtime:2.3.0"
    kapt "androidx.room:room-compiler:2.3.0"
    // Hilt dependencies
    implementation "com.google.dagger:hilt-android:$hilt_version"
    kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
}

在項(xiàng)目中使用hilt

Step1:使用@HiltAndroidApp注解

新建繼承自Application的類并添加注解@HiltAndroidApp,觸發(fā) Hilt 的代碼生成,其中包括可以使用依賴項(xiàng)注入的應(yīng)用基類。應(yīng)用容器是應(yīng)用的父容器,這意味著其他容器可以訪問其提供的依賴項(xiàng)。

@HiltAndroidApp 
class LogApplication : Application()

Step2:使用@AndroidEntryPoint將依賴注入Android類

在 Application 類中設(shè)置了 Hilt 且有了應(yīng)用級組件后,Hilt 可以為帶有 @AndroidEntryPoint 注解的其他 Android 類提供依賴項(xiàng)。Hilt 目前支持以下 Android 類:

  • Application(通過使用 @HiltAndroidApp)
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

如果您使用 @AndroidEntryPoint 為某個 Android 類添加注解,則還必須為依賴于該類的 Android 類添加注解。例如,如果您為某個 Fragment 添加注解,則還必須為使用該 Fragment 的所有 Activity 添加注解。

@AndroidEntryPoint 
class LogsFragment : Fragment() { .... }

Step3:使用hilt進(jìn)行字段注入

@Inject 注解讓 Hilt 注入不同類型的實(shí)例。其實(shí)就是聲明變量的時候用上這個注解

@AndroidEntryPoint
class LogsFragment : Fragment() {
    @Inject lateinit var logger: LoggerLocalDataSource
    @Inject lateinit var dateFormatter: DateFormatter
    ...
}

Step4:Hilt提供實(shí)例

step4-condition1:在構(gòu)造器上利用@Inject獲取實(shí)例。

對于用@Inject注解的變量,提供其實(shí)例時,如果是通過構(gòu)造器創(chuàng)建的實(shí)例那么我們可以直接在構(gòu)造器上利用@Inject注解就可以讓hilt為我們創(chuàng)建類的實(shí)例,比如下面的DateFormatter

/**
 * 通過構(gòu)造器創(chuàng)建依賴
 */
class DateFormatter @Inject constructor() {
    @SuppressLint("SimpleDateFormat")
    private val formatter = SimpleDateFormat("d MMM yyyy HH:mm:ss")
    fun formatDate(timestamp: Long): String {
        return formatter.format(Date(timestamp))
    }
}

再比如Step3中的logger。它與DateFormatter的區(qū)別在于它的構(gòu)造參數(shù)是有參數(shù)的。那么對于這種情況,我們還需要告訴hilt如何獲取LogDao的實(shí)例。也就是說如果LogDao能通過構(gòu)造器構(gòu)建的話,直接添加@Inject注解就可以了。但是這里的logDao是一個接口,而且它無法手動添加實(shí)現(xiàn)類(這個是Android room中的DAO)。所以我們需要使用其他的方式獲取

@Singleton
class LoggerLocalDataSource @Inject constructor(private val logDao: LogDao) {
    ...
}

step4-condition2:用 @Provides 提供實(shí)例

我們可以在 Hilt 模塊中用 @Provides 注釋函數(shù),以告訴 Hilt 如何提供無法注入構(gòu)造函數(shù)的 類型。hilt模塊也就是用@Module 和 @InstallIn 注釋的類的使用。無法通過對構(gòu)造器添加@Inject注解方式提供實(shí)例時通過@Module和@InstallIn(指定作用域)來聲明提供對象實(shí)例的方式。 這個Module是模塊,我們需要使用模塊向 Hilt 添加綁定,換句話說,就是告訴 Hilt 如何提供不同類型的實(shí)例。 在 Hilt 模塊中,您需針對無法注入構(gòu)造函數(shù)的類型(如項(xiàng)目中未包含的接口或類)添加綁定。例如 OkHttpClient - 您需要使用其構(gòu)建器來創(chuàng)建實(shí)例。因?yàn)檫@里實(shí)際上是提供數(shù)據(jù)庫操作,所以作用域應(yīng)該是全局的,所以采用的是SingletonComponent。這里還有其他的component

@InstallIn(SingletonComponent::class)
@Module
object DatabaseModule {
//這個可以是個class,但是在 Kotlin 中,只包含 @Provides 函數(shù)的模塊可以是 object 類。
//這樣,提供程序即會得到優(yōu)化,并幾乎可以內(nèi)聯(lián)在生成的代碼中。
    /**
     * 用 @Provides 提供實(shí)例。我們可以在 Hilt 模塊中用 @Provides 注釋函數(shù),
     * 以告訴 Hilt 如何提供無法注入構(gòu)造函數(shù)的 類型。
     */
    @Provides
    fun provideLogDao(database: AppDatabase): LogDao {
//
        return database.logDao()
        //Hilt 可從上述代碼中得知,在提供 LogDao 的實(shí)例時需要執(zhí)行 database.logDao()。
        //由于我們擁有 AppDatabase 作為傳遞依賴項(xiàng),因此我們還需要告訴 Hilt 如何提供這種類型的實(shí)例。
    }
    //因?yàn)槲覀円恢毕M?Hilt 提供相同的數(shù)據(jù)庫實(shí)例,所以我們用 @Singleton 注釋 @Provides provideDatabase 方法。
    @Provides
    @Singleton
    fun provideDatabase(@ApplicationContext context: Context):AppDatabase{
        return Room.databaseBuilder(
            context,
            AppDatabase::class.java,
            "logging.db"
        ).build()
    }
}

step4-condition3:用 @Binds 提供接口。

對于接口我們不能使用構(gòu)造函數(shù)注入。 要告訴 Hilt 對接口使用什么實(shí)現(xiàn),可以在 Hilt 模塊內(nèi)的函數(shù)上使用 @Binds 注釋。@Binds必須對抽象函數(shù)作出注釋(因?yàn)樵摵瘮?shù)是抽象的,因此其中不包含任何代碼,并且該類也必須是抽象的)。抽象函數(shù)的返回類型是我們要為其提供實(shí)現(xiàn)的接口(即 AppNavigator)。通過添加具有接口實(shí)現(xiàn)類型(即 AppNavigatorImpl)的唯一參數(shù)來指定實(shí)現(xiàn)。比如在MainActivity中我們依賴的接口

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    @Inject
    lateinit var navigator: AppNavigator
    ....
}

所以對此我們需要新建module使用@Binds獲取,如果類型有作用域,則@Binds 方法必須有作用域注釋

//我們的新導(dǎo)航信息(即 AppNavigator)需要特定于 Activity 的信息
//(因?yàn)?AppNavigatorImpl 擁有 Activity 作為依賴項(xiàng))。
// 因此,我們必須將其安裝在 Activity 容器中,而不是安裝在 Application 容器中,因?yàn)檫@是有關(guān) Activity 的信息所在。
@InstallIn(ActivityComponent::class)
@Module
abstract class NavigationModule {
    @Binds
    abstract fun provideNavigator(impl: AppNavigatorImpl):AppNavigator
    //參數(shù)為具體的實(shí)現(xiàn)類,所以要告知hilt如何提供實(shí)現(xiàn)類的實(shí)例。下面的實(shí)現(xiàn)類通過構(gòu)造函數(shù)提供實(shí)例
}
//======AppNavigatorImpl.ktx========//
//AppNavigatorImpl 會依賴于 FragmentActivity。由于系統(tǒng)會在 Activity 容器中提供 AppNavigator 實(shí)例
// (亦可用于 Fragment 容器和 View 容器,因?yàn)?NavigationModule 會安裝在 ActivityComponent 中),所以 FragmentActivity 目前可用
class AppNavigatorImpl @Inject constructor(private val activity: FragmentActivity) : AppNavigator {
    override fun navigateTo(screen: Screens) {
        val fragment = when (screen) {
            Screens.BUTTONS -> ButtonsFragment()
            Screens.LOGS -> LogsFragment()
        }
        activity.supportFragmentManager.beginTransaction()
            .replace(R.id.main_container, fragment)
            .addToBackStack(fragment::class.java.canonicalName)
            .commit()
    }
}

step4-condition4:使用限定符

要告訴 Hilt 如何提供相同類型的不同實(shí)現(xiàn)(多個綁定),可以使用限定符。它的定義其實(shí)就是注解。

@Qualifier 
annotation class InMemoryLogger 
@Qualifier 
annotation class DatabaseLogger

要比如對log的增刪查提供一套基于內(nèi)存的實(shí)現(xiàn)方式,那么定義接口

interface LogDataSource {
    fun addLog(msg: String)
    fun getAllLogs(callback: (List<Log>) -> Unit)
    fun removeLogs()
}

基于Room的實(shí)現(xiàn)如下,其實(shí)就是開篇提到的實(shí)現(xiàn),只不過實(shí)現(xiàn)了該接口

@Singleton
class LoggerLocalDataSource @Inject constructor(private val logDao: LogDao):LogDataSource {
    private val executorService: ExecutorService = Executors.newFixedThreadPool(4)
    private val mainThreadHandler by lazy {
        Handler(Looper.getMainLooper())
    }
    override fun addLog(msg: String) {
        executorService.execute {
            logDao.insertAll(
                Log(
                    msg,
                    System.currentTimeMillis()
                )
            )
        }
    }
    override fun getAllLogs(callback: (List<Log>) -> Unit) {
        executorService.execute {
            val logs = logDao.getAll()
            mainThreadHandler.post { callback(logs) }
        }
    }
    override fun removeLogs() {
        executorService.execute {
            logDao.nukeTable()
        }
    }
}

基于內(nèi)存的實(shí)現(xiàn)如下

@ActivityScoped
class LoggerInMemoryDataSource @Inject constructor():LogDataSource {
    private val logs = LinkedList<Log>()
    override fun addLog(msg: String) {
        logs.addFirst(Log(msg, System.currentTimeMillis()))
    }
    override fun getAllLogs(callback: (List<Log>) -> Unit) {
        callback(logs)
    }
    override fun removeLogs() {
        logs.clear()
    }
}

基于上面介紹,使用接口時我們定義實(shí)現(xiàn)類如下

@Module
@InstallIn(SingletonComponent::class)
abstract class LoggingDatabaseModule {
    @DatabaseLogger
    @Binds
    @Singleton
    abstract fun bindDatabaseLogger(impl: LoggerLocalDataSource): LogDataSource
}
@Module
@InstallIn(ActivityComponent::class)
abstract class LoggingInMemoryModule {
    @InMemoryLogger
    @Binds
    @ActivityScoped
    abstract fun bindInMemoryLogger(impl: LoggerInMemoryDataSource): LogDataSource
}

可以看到我們定義了兩個module,之所以不是一個module是因?yàn)閮煞N實(shí)現(xiàn)的作用域不一樣。而且在InMemory的@Binds方法上我們還加入了@ActivityScoped,這個是必須加入的,因?yàn)閷?shí)現(xiàn)類中指定了作用域。同理在這兒我們還加入了自定義的注解InMemoryLogger,就是告訴hilt選擇那種方式提供實(shí)例。如果不加限定符的話會報錯。真正使用該接口時如下

class ButtonsFragment : Fragment() {
    @InMemoryLogger
    @Inject lateinit var logger: LogDataSource
    ...
}

可以看到與Step3中的區(qū)別在于此處變量的類型為接口而不是具體的實(shí)現(xiàn),其次加入了限定符。綜上就是Hilt的基本使用

到此這篇關(guān)于Android中Hilt的使用詳解的文章就介紹到這了,更多相關(guān)Android Hilt內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android全面屏與異形(劉海)屏的適配教程

    Android全面屏與異形(劉海)屏的適配教程

    Apple一直在引領(lǐng)設(shè)計的潮流,自從 iPhone X 發(fā)布之后,各種異形屏、劉海屏也都出來,下面這篇文章主要給大家分享介紹了關(guān)于Android全面屏與異形(劉海)屏的適配教程,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-07-07
  • Android 判斷日期是否在一年以內(nèi)的算法實(shí)例

    Android 判斷日期是否在一年以內(nèi)的算法實(shí)例

    下面小編就為大家?guī)硪黄狝ndroid 判斷日期是否在一年以內(nèi)的算法實(shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • kotlin使用Dagger2的過程全紀(jì)錄

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

    Dagger2是一款基于Java注解,在編譯階段完成依賴注入的開源庫,主要用于模塊間解耦,方便進(jìn)行測試。下面這篇文章主要給大家介紹了關(guān)于kotlin使用Dagger2的過程的相關(guān)資料,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03
  • Android消息機(jī)制Handler的工作過程詳解

    Android消息機(jī)制Handler的工作過程詳解

    這篇文章主要為大家詳細(xì)介紹了Android消息機(jī)制Handler的工作過程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • Android異步上傳圖片到PHP服務(wù)器

    Android異步上傳圖片到PHP服務(wù)器

    這篇文章主要介紹了Android異步上傳圖片到PHP服務(wù)器的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • android I/0流操作文件(文件存儲)

    android I/0流操作文件(文件存儲)

    Java提供一套完整的I/О流體系,通過I/О流可以非常方便地訪問磁盤中的文件,同樣Android 也支持I/O流方式來訪問手機(jī)等移動設(shè)備中的存儲文件。希望可以為大家提供幫助
    2021-06-06
  • Android中傳值Intent與Bundle的區(qū)別小結(jié)

    Android中傳值Intent與Bundle的區(qū)別小結(jié)

    這篇文章主要給大家總結(jié)介紹了關(guān)于Android中傳值Intent與Bundle的區(qū)別,文中通過示例代碼以及圖文介紹的非常詳細(xì),對各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Android設(shè)置改變透明度實(shí)例

    Android設(shè)置改變透明度實(shí)例

    在Android開發(fā)中,透明度是很常見的一個屬性,是指控制一個視圖的不透明程度,取值范圍從0到255,通過設(shè)置透明度能夠?qū)崿F(xiàn)圖片、控件等UI元素的顯示效果的調(diào)整,Android透明度對照表是開發(fā)過程中常用的工具之一,它能夠幫助開發(fā)人員快速了解設(shè)置透明度的數(shù)值范圍
    2023-11-11
  • Android基礎(chǔ)之使用Fragment適應(yīng)不同屏幕和分辨率(分享)

    Android基礎(chǔ)之使用Fragment適應(yīng)不同屏幕和分辨率(分享)

    以下是對Fragment的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下
    2013-07-07
  • 實(shí)例詳解Android中JNI的使用方法

    實(shí)例詳解Android中JNI的使用方法

    JNI是Java Native Interface的縮寫,它提供若干的API實(shí)現(xiàn)Java與其他語言之間的通信,這篇文章主要給大家介紹了關(guān)于Android中JNI的使用方法,需要的朋友可以參考下
    2021-08-08

最新評論