Hilt - Ki-Kobayashi/Android-Wiki GitHub Wiki
🟩 Hiltの解説(公式)
https://developer.android.com/training/dependency-injection/hilt-android?hl=ja#hilt-and-dagger
🟩 Hiltの導入
※事前にKSPを導入しておく https://developer.android.com/training/dependency-injection/hilt-android?hl=ja
🟡app / build.gradle
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")// https://github.com/google/secrets-gradle-plugin/tree/main
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
id("com.google.devtools.ksp")
id("com.google.dagger.hilt.android") 👈追加
}
dependencies {
・・・
// TODO: 🚨Composeで使用するときは、**「2.48以上」**にしないとエラーがになる
val hilt_version = "2.48"
implementation("com.google.dagger:hilt-android:$hilt_version")
ksp("com.google.dagger:hilt-android-compiler:$hilt_version")
implementation("androidx.hilt:hilt-navigation-compose:1.1.0")
🟡proj / build.gradle
plugins {
id("com.android.application") version "8.2.0" apply false
id("org.jetbrains.kotlin.android") version "1.9.0" apply false
id("com.google.dagger.hilt.android") version "2.48" apply false 👈追加
id("com.google.devtools.ksp") version "1.9.0-1.0.12"
}
🟩 Applicationクラスを追加する
@HiltAndroidApp
class JetTodoApp : Application() {
}
🟡Manifestにも追加
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.JetTodo2"
tools:targetApi="34"
android:name=".JetTodoApp"> 👈追加
🟩 クラス名の上にアノテーションの追加
@AndroidEntryPoint
- Activity
- Fragment
- View
- Service
- BroadcastReceiver
@HiltViewModel
- ViewModel
@Module
、@InstallIn(XxxxComponent::class)
- XxxxModuleクラス(インスタンスの作成方法を知らせるクラス※後述)
@EntryPoint
、@InstallIn(XxxxComponent::class)
- Hilt でサポートされていないクラスにDIする場合に使用(例:コンテンツ プロバイダ)
🟡
🟩 @Module(Hiltモジュール) / モジュール内で使用するアノテーション
https://developer.android.com/training/dependency-injection/hilt-android?hl=ja#hilt-modules
@Module
が 必要なのは、以下の2つのケース
🟡- インターフェースの場合
→ コンストラクタ インジェクションができない(作り方しらない)ため、DIするには作り方を教える必要がある
→@Binds
を使用
→ 例: Room使用時の Repository/RepositoryImpl
.
- 外部ライブラリのクラスなど、自分が所有していない型の場合
→ コンストラクタ インジェクションができない(作り方しらない)ため、DIするには作り方を教える必要がある
→@Provides
を使用
→ 例: Room, Retrofit, Moshiなどのライブラリのインスタンス生成、Builder パターンでインスタンスを作成する必要がある場合
.
🟡 @Provides
https://developer.android.com/training/dependency-injection/hilt-android?hl=ja#inject-provides
このアノテーションつけた関数の型のインスタンスを作成したときに、自動的に関数内の処理もやるよっていう指定
@Module
@InstallIn(SingletonComponent::class)
object ApiModule {
/**
* Retrofit2でデバッグ用にログ出力する設定
* https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor
* https://square.github.io/okhttp/features/interceptors/
*
* ◆ログレベル
* logger.levelで渡しているlevelには4種あり、出力の詳細さが変わる
* ★ NONE
* ログを出力しない
* ★ BASIC
* リクエストラインとレスポンスラインのみを出力
* ★ HEADER
* BASICのログに加えてリクエストヘッダとレスポンスヘッダが出力される
* ★ BODY
* HEADERのログに加えて、クエストボディとレスポンスボディが出力される
*/
@Singleton
@Provides
fun provideOkhttpClient(): OkHttpClient {
val logInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
return OkHttpClient.Builder()
.addInterceptor {
// 💡【下記処理について】
// 特にリクエストに変更を加えたいが元のリクエストを変更せずに残したい場合に有用な処理
// リクエストからHTTPのURLを取得
val httpUrl = it.request().url
// 元のリクエストからコピーを作成し、url(httpUrl)メソッドを使用して新しいURLに更新
val requestBuilder = it.request().newBuilder().url(httpUrl)
// 更新されたリクエストを使って処理を継続
it.proceed(requestBuilder.build())
}
.addInterceptor(logInterceptor)
.readTimeout(10, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.build()
}
@Singleton
@Provides
fun provideMoshi(): MoshiConverterFactory {
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
return MoshiConverterFactory.create(moshi)
}
@Singleton
@Provides
fun provideRetrofit(moshiConverterFactory: MoshiConverterFactory): Retrofit {
return Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.addConverterFactory(moshiConverterFactory)
.build()
}
@Singleton
@Provides
fun provideNewsApiService(retrofit: Retrofit): NewsApiService =
retrofit.create(NewsApiService::class.java)
}
🟡 @Binds
https://developer.android.com/training/dependency-injection/hilt-android?hl=ja#inject-interfaces
インターフェースの場合は、コンストラクタ インジェクションができません。
代わりに、Hilt モジュール内に @Binds アノテーションを付けた抽象関数を作成する
- 関数の戻り値の型で、その関数が提供するインターフェースのインスタンスを知らせます。
- 関数のパラメータで、提供する実装を知らせます
🟡インターフェースの実装クラス
class AnalyticsServiceImpl @Inject constructor(
...
) : AnalyticsService { ... }
🟡Moduleクラス
@Module
@InstallIn(ActivityComponent::class) 👈AnalyticsModule 内のすべての依存関係が、アプリの"Activity内のみ(すべて)"で使用できるという意味
abstract class AnalyticsModule {
@Binds
abstract fun bindAnalyticsService(
analyticsServiceImpl: AnalyticsServiceImpl
): AnalyticsService
}
.
🟡 @InstallIn アノテーション
App内のどの範囲のクラスにDIするかを限定するやつ
https://developer.android.com/training/dependency-injection/hilt-android?hl=ja#component-default
https://developer.android.com/training/dependency-injection/hilt-android?hl=ja#generated-components
.
🟩
🟡
.
🟩
🟡
.
🟩
🟡
.
🟩
🟡
.
🟩
🟡
.
🟩
🟡
.
🟩
🟡
.