[Android] 027. Hilt(DI)

DI(依存性注入)をHiltで追加してみます
今回もごちゃごちゃやらず最低限必要なところだけサクッと実装です

アノテーションチートシート
https://developer.android.com/images/training/dependency-injection/hilt-annotations.pdf

com.google.dagger:hiltの場合

developerの説明は以下
https://developer.android.com/training/dependency-injection/hilt-android?hl=ja

依存関係の設定

以下をProject Structureなどでimplementationします

com.google.dagger:hilt-android
com.google.dagger:hilt-android-compiler

またhiltViewModel()を使用するため以下もimplementationします
androidx.hilt:hilt-navigation-compose (1.1.0-alpha01以降)

lib.versions.tomlの修正もしときます

[versions]
hilt = "2.48"

[libraries]
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }

[plugins]
com-google-dagger-hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }

build.gradleの設定

kaptの設定をします
kotlin(“kapt”)の設定設定を入力したらいったんSyncして有効にしてからkapt設定してください

ksp対応は現在α版のようです
https://dagger.dev/dev-guide/ksp.html

plugins {
    alias(libs.plugins.com.google.dagger.hilt.android) apply false
}
plugins {
    kotlin("kapt")
    alias(libs.plugins.com.google.dagger.hilt.android)
}

kapt {
    correctErrorTypes = true
}

dependencies {
    implementation(libs.hilt.android)
    kapt(libs.hilt.compiler)
}

Applicationクラスの追加

@HiltAndroidAppアノテーションをつけたApplicationクラスの追加します

/**
 * ```AndroidManifest.xml
 * <application
 *     android:name=".Application"
 * ```
 */
@HiltAndroidApp
class Application : android.app.Application() {
    override fun onCreate() {
        super.onCreate()
    }
}

Activityの設定

Activityに@AndroidEntryPointアノテーションをつけます
これで準備完了です

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    ...
}

実装

とりあえず最小構成と思われる実装
以前紹介したContenerの変わりにModuleを追加する感じです

ビルド成功すると自動生成されたJavaのコードができるので確認してみてください

interface Repository {
    fun test()
}

class DefaultRepository @Inject constructor() : Repository {
    override fun test() {
        Log.d("App", "test")
    }
}

// シングルトンの場合object
@Module
@InstallIn(ViewModelComponent::class)
object RepositoryBindModule {
    @Provides
    fun defaultRepository(): Repository {
        return DefaultRepository()
    }
}
// または以下の実装
/*
@Module
@InstallIn(ViewModelComponent::class)
abstract class RepositoryBindModule {
    @Singleton
    @Binds
    abstract fun defaultRepository(repo: DefaultRepository): Repository
}
*/

@HiltViewModel
class MainViewModel @Inject constructor(
    private val repo: DefaultRepository
) : ViewModel() {
    fun test() {
        repo.test()
    }
}

@Composable
fun AppScreen(
    modifier: Modifier = Modifier,
    viewModel: MainViewModel = hiltViewModel(),
) {
    LaunchedEffect(Unit) {
        viewModel.test()
    }

    //...
}

androidx.hiltの場合

※ @Binds / @Providesあたりがcom.google.daggerのHiltと同じ実装だと正しく動作してないようでandroidx版の実装方法のサンプルも無く現時点では使い方がわかりません…とりあえず動作できたところまでです

jetpack版の開発も着々と進んでいるようですが、まだ開発段階なのでJetpack Compose環境のDIは手動が良さそう

developerの説明は以下
https://developer.android.com/training/dependency-injection/hilt-jetpack
https://developer.android.com/jetpack/androidx/releases/hilt

依存関係追加

以下をProject Structureなどでimplementationします

androidx.hilt:hilt-common
androidx.hilt:hilt-compiler

またhiltViewModel()を使用するため以下もimplementationします
androidx.hilt:hilt-navigation-compose (1.1.0-alpha01以降)

またkspにも対応しているのでkspの設定も追加します

[versions]
hilt = "1.1.0-alpha01"
com-google-devtools-ksp = "1.9.0-1.0.13"

[libraries]
androidx-hilt-common = { group = "androidx.hilt", name = "hilt-common", version.ref = "androidx-hilt" }
androidx-hilt-compiler = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "androidx-hilt" }
androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version = "1.1.0-alpha01" }

[plugins]
com-google-devtools-ksp = {id = "com.google.devtools.ksp", version.ref = "com-google-devtools-ksp" }

build.gradleの設定

plugins {
    alias(libs.plugins.com.google.devtools.ksp) apply false
}
plugins {
    alias(libs.plugins.com.google.devtools.ksp)
}

dependencies {
    implementation(libs.androidx.hilt.common)
    ksp(libs.androidx.hilt.compiler)
    implementation(libs.androidx.hilt.navigation.compose)
}

実装

/**
 * ```AndroidManifest.xml
 * <application
 *     android:name=".Application"
 * ```
 */
@HiltAndroidApp
class Application : android.app.Application() {
    override fun onCreate() {
        super.onCreate()
    }
}

@HiltViewModel
class MainViewModel @Inject constructor() : ViewModel() {
    fun test() {
        Log.d("App", "test")
    }
}

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // ComponentActivity.viewModelsでも取得できる
        val viewModel: MainViewModel by viewModels()
        viewModel.test()
    ...
}

@Composable
fun AppScreen(
    modifier: Modifier = Modifier,
    viewModel: MainViewModel = hiltViewModel()
){
    LaunchedEffect(Unit) {
        viewModel.test()
    }
}

Android Studio Giraffe 2022.3.1 Patch 1 built on August 17, 2023