最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android中Hilt的使用詳解

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

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

Hilt 通過為項(xiàng)目中的每個(gè) Android 類提供容器并自動(dòng)管理其生命周期,提供了一種在應(yīng)用中使用 DI(依賴項(xiàng)注入)的標(biāo)準(zhǔn)方法。Hilt 在熱門 DI 庫 Dagger 的基礎(chǔ)上構(gòu)建而成,因而能夠受益于 Dagger 的編譯時(shí)正確性、運(yùn)行時(shí)性能、可伸縮性和 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 為某個(gè) Android 類添加注解,則還必須為依賴于該類的 Android 類添加注解。例如,如果您為某個(gè) Fragment 添加注解,則還必須為使用該 Fragment 的所有 Activity 添加注解。

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

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

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

@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í)例時(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是一個(gè)接口,而且它無法手動(dòng)添加實(shí)現(xiàn)類(這個(gè)是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í)例時(shí)通過@Module和@InstallIn(指定作用域)來聲明提供對象實(shí)例的方式。 這個(gè)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 {
//這個(gè)可以是個(gè)class,但是在 Kotlin 中,只包含 @Provides 函數(shù)的模塊可以是 object 類。
//這樣,提供程序即會(huì)得到優(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í)例時(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 會(huì)依賴于 FragmentActivity。由于系統(tǒng)會(huì)在 Activity 容器中提供 AppNavigator 實(shí)例
// (亦可用于 Fragment 容器和 View 容器,因?yàn)?NavigationModule 會(huì)安裝在 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)(多個(gè)綁定),可以使用限定符。它的定義其實(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í)我們定義實(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
}

可以看到我們定義了兩個(gè)module,之所以不是一個(gè)module是因?yàn)閮煞N實(shí)現(xiàn)的作用域不一樣。而且在InMemory的@Binds方法上我們還加入了@ActivityScoped,這個(gè)是必須加入的,因?yàn)閷?shí)現(xiàn)類中指定了作用域。同理在這兒我們還加入了自定義的注解InMemoryLogger,就是告訴hilt選擇那種方式提供實(shí)例。如果不加限定符的話會(huì)報(bào)錯(cuò)。真正使用該接口時(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開發(fā)之禁止下拉通知欄的方法

    Android開發(fā)之禁止下拉通知欄的方法

    這篇文章主要介紹了Android開發(fā)之禁止下拉通知欄的方法,實(shí)例分析了Android權(quán)限控制與Activity相應(yīng)設(shè)置技巧,需要的朋友可以參考下
    2016-01-01
  • Android 中的注解詳細(xì)介紹

    Android 中的注解詳細(xì)介紹

    本文主要介紹 Android 中的注解,這里整理詳細(xì)的資料來說明Android注解是如何使用,提高編程效率,有興趣的小伙伴可以參考下
    2016-08-08
  • Android?Material組件庫日期選擇和時(shí)間選擇器的使用方法

    Android?Material組件庫日期選擇和時(shí)間選擇器的使用方法

    這篇文章主要介紹了Android?Material組件庫(日期選擇和時(shí)間選擇器)基本使用,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-11-11
  • Android 操作系統(tǒng)獲取Root權(quán)限 原理詳細(xì)解析

    Android 操作系統(tǒng)獲取Root權(quán)限 原理詳細(xì)解析

    許多機(jī)友新購來的Android機(jī)器沒有破解過Root權(quán)限,無法使用一些需要高權(quán)限的軟件,以及進(jìn)行一些高權(quán)限的操作,其實(shí)破解手機(jī)Root權(quán)限是比較簡單及安全的,破解Root權(quán)限的原理就是在手機(jī)的/system/bin/或/system/xbin/目錄下放置一個(gè)可執(zhí)行文件“su”
    2013-10-10
  • Android筆記之:App應(yīng)用之發(fā)布各廣告平臺(tái)版本的詳解

    Android筆記之:App應(yīng)用之發(fā)布各廣告平臺(tái)版本的詳解

    Android的廣告平臺(tái)是很多的,各市場對各平臺(tái)的接受程度是不一樣的,Android的開發(fā)者如果想集成廣告基本要考慮下面兩個(gè)問題
    2013-04-04
  • Android?WebView軟鍵盤遮擋輸入框方案詳解

    Android?WebView軟鍵盤遮擋輸入框方案詳解

    這篇文章主要介紹了Android?WebView軟鍵盤遮擋輸入框方案詳解,本文提供了一種新的解決?WebView?輸入框被軟鍵盤遮擋的思路,不過這種思路也有它的局限性,目前來看僅適用于全屏的?WebView?中,需要的朋友可以參考下
    2022-06-06
  • Android?中的?Timer?和?TimerTask詳解

    Android?中的?Timer?和?TimerTask詳解

    Timer?是?Java?中用于創(chuàng)建定時(shí)任務(wù)的類,它位于?java.util?包中,可以使用Timer來安排一次性或定期執(zhí)行的任務(wù),這篇文章主要介紹了Android?的?Timer?和?TimerTask,需要的朋友可以參考下
    2024-05-05
  • Android中的Retrofit+OkHttp+RxJava緩存架構(gòu)使用

    Android中的Retrofit+OkHttp+RxJava緩存架構(gòu)使用

    Retrofit和OkHttp API以及JVM擴(kuò)展RxJava都是開源項(xiàng)目,大家可以輕松在GitHub上找到,下載和基本配置部分這里我們不作重點(diǎn),主要還是來看一下Android中的Retrofit+OkHttp+RxJava緩存架構(gòu)使用:
    2016-06-06
  • Android保存聯(lián)系人到通訊錄的方法

    Android保存聯(lián)系人到通訊錄的方法

    怎么保存聯(lián)系人數(shù)據(jù)到本機(jī)通訊錄?這篇文章主要為大家詳細(xì)介紹了Android保存聯(lián)系人到通訊錄的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Android開發(fā)中超好用的正則表達(dá)式工具類RegexUtil完整實(shí)例

    Android開發(fā)中超好用的正則表達(dá)式工具類RegexUtil完整實(shí)例

    這篇文章主要介紹了Android開發(fā)中超好用的正則表達(dá)式工具類RegexUtil,結(jié)合完整實(shí)例形式分析了Android正則表達(dá)式常見操作技巧,包括針對證件號、銀行賬號、手機(jī)號、郵編等的正則判斷相關(guān)操作技巧,需要的朋友可以參考下
    2017-11-11

最新評論

安陆市| 屏东县| 衢州市| 博罗县| 鹤峰县| 凉城县| 合川市| 海淀区| 北流市| 昌江| 长垣县| 永城市| 比如县| 汝南县| 拉萨市| 礼泉县| 韩城市| 千阳县| 甘肃省| 台湾省| 攀枝花市| 沁源县| 孙吴县| 崇仁县| 绥芬河市| 宾川县| 五家渠市| 衡水市| 宁河县| 玉溪市| 嘉禾县| 岱山县| 玛曲县| 仲巴县| 辽阳市| 澜沧| 普宁市| 双城市| 石柱| 汤阴县| 肥乡县|