Hilt は Android 用の依存関係インジェクション ライブラリです。これを使うことで、プロジェクトで依存関係の注入(DI)を手動で行うためのボイラープレートが減ります。手動で依存関係の注入を行うには、すべてのクラスとその依存関係を手作業で作成し、コンテナを使用して依存関係の再利用と管理を行う必要があります。
Hilt は、プロジェクト内のすべての Android クラスにコンテナを提供し、そのライフサイクルを自動で管理することで、アプリケーションで DI を行うための標準的な方法を提供します。Hilt は、よく知られた DI ライブラリである Dagger の上に構築されているため、コンパイル時の正確性、実行時のパフォーマンス、スケーラビリティ、Android Studio のサポートといった Dagger の恩恵を受けられます。詳細については、Hilt と Dagger をご覧ください。
このガイドでは、Hilt とそこで生成されるコンテナの基本概念について説明します。また、既存のアプリで Hilt を使用できるようにする方法も紹介します。
依存関係を追加する
まず、hilt-android-gradle-plugin
プラグインをプロジェクトのルート build.gradle
ファイルに追加します。
Groovy
plugins { ... id 'com.google.dagger.hilt.android' version '2.51.1' apply false }
Kotlin
plugins { ... id("com.google.dagger.hilt.android") version "2.51.1" apply false }
次に、Gradle プラグインを適用し、app/build.gradle
ファイルに次の依存関係を追加します。
Groovy
... plugins { id 'kotlin-kapt' id 'com.google.dagger.hilt.android' } android { ... } dependencies { implementation "com.google.dagger:hilt-android:2.51.1" kapt "com.google.dagger:hilt-compiler:2.51.1" } // Allow references to generated code kapt { correctErrorTypes true }
Kotlin
plugins { id("kotlin-kapt") id("com.google.dagger.hilt.android") } android { ... } dependencies { implementation("com.google.dagger:hilt-android:2.51.1") kapt("com.google.dagger:hilt-android-compiler:2.51.1") } // Allow references to generated code kapt { correctErrorTypes = true }
Hilt は Java 8 の機能を使用しています。プロジェクトで Java 8 を有効にするには、app/build.gradle
ファイルに次の内容を追加します。
Groovy
android { ... compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } }
Kotlin
android { ... compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } }
Hilt アプリケーション クラス
Hilt を使用するアプリには、@HiltAndroidApp
アノテーションが付けられた Application
クラスが含まれている必要があります。
@HiltAndroidApp
は、Hilt のコード生成をトリガーします。これには、アプリケーション レベルの依存関係コンテナとして機能するアプリケーションの基本クラスも含まれます。
Kotlin
@HiltAndroidApp class ExampleApplication : Application() { ... }
Java
@HiltAndroidApp public class ExampleApplication extends Application { ... }
ここで生成された Hilt コンポーネントは、Application
オブジェクトのライフサイクルにアタッチされ、依存関係を提供します。また、アプリの親コンポーネントであることから、他のコンポーネントがこのコンポーネントの提供する依存関係にアクセスできます。
Android クラスに依存関係を注入する
Application
クラスで Hilt がセットアップされ、アプリケーション レベルのコンポーネントが利用可能になると、@AndroidEntryPoint
アノテーションが付けられた他の Android クラスに依存関係を提供できるようになります。
Kotlin
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { ... }
現在、Hilt は以下の Android クラスをサポートしています。
Application
(@HiltAndroidApp
を使用)ViewModel
(@HiltViewModel
を使用)Activity
Fragment
View
Service
BroadcastReceiver
Android クラスに @AndroidEntryPoint
アノテーションを付ける場合は、それに依存する Android クラスにもアノテーションを付ける必要があります。たとえば、フラグメントにアノテーションを付ける場合は、そのフラグメントを使用するアクティビティにもアノテーションを付ける必要があります。
@AndroidEntryPoint
は、プロジェクト内の Android クラスごとに個別の Hilt コンポーネントを生成します。これらのコンポーネントは、コンポーネント階層で説明されているように、それぞれの親クラスから依存関係を受け取ることができます。
コンポーネントから依存関係を取得するには、@Inject
アノテーションを使用してフィールド インジェクションを行います。
Kotlin
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { @Inject lateinit var analytics: AnalyticsAdapter ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { @Inject AnalyticsAdapter analytics; ... }
Hilt が注入するクラスには、インジェクションを使用する他の基本クラスを含めることができます。抽象クラスの場合、@AndroidEntryPoint
アノテーションは不要です。
Android クラスが注入されるライフサイクル コールバックの詳細については、コンポーネントのライフタイムをご覧ください。
Hilt バインディングを定義する
フィールド インジェクションを実行するには、対応するコンポーネントからの必要な依存関係のインスタンス提供方法を Hilt で把握している必要があります。バインディングには、型のインスタンスを依存関係として提供するために必要な情報が含まれています。
Hilt にバインディング情報を提供する方法の 1 つとして、コンストラクタ インジェクションがあります。クラスのコンストラクタで @Inject
アノテーションを使用して、そのクラスのインスタンス提供方法を Hilt に知らせます。
Kotlin
class AnalyticsAdapter @Inject constructor( private val service: AnalyticsService ) { ... }
Java
public class AnalyticsAdapter { private final AnalyticsService service; @Inject AnalyticsAdapter(AnalyticsService service) { this.service = service; } ... }
クラスのアノテーションが付けられたコンストラクタのパラメータは、そのクラスの依存関係です。この例では、AnalyticsAdapter
に依存関係として AnalyticsService
が指定されています。したがって、Hilt は AnalyticsService
インスタンスの提供方法も把握している必要があります。
Hilt モジュール
場合によっては、型へのコンストラクタ インジェクションができないことがあります。これにはいくつかの理由が考えられます。たとえば、インターフェースの場合は、コンストラクタ インジェクションができません。また、外部ライブラリのクラスなど、自分が所有していない型の場合も、コンストラクタ インジェクションができません。このような場合は、Hilt モジュールを使用して、Hilt にバインディング情報を提供します。
Hilt モジュールは、@Module
アノテーションが付けられたクラスです。Dagger モジュールと同じように、特定の型のインスタンスの提供方法を Hilt に知らせるものです。Dagger モジュールとは異なり、Hilt モジュールは @InstallIn
アノテーションを付けて、各モジュールが使用またはインストールされる Android クラスを知らせる必要があります。
Hilt モジュールで提供する依存関係は、その Hilt モジュールをインストールした Android クラスに関連付けられている、すべての生成されたコンポーネントで使用できます。
@Binds を使用してインターフェース インスタンスを注入する
AnalyticsService
の例を考えてみましょう。AnalyticsService
がインターフェースの場合は、コンストラクタ インジェクションができません。代わりに、Hilt モジュール内に @Binds
アノテーションを付けた抽象関数を作成して、バインディング情報を提供します。
@Binds
アノテーションは、インターフェースのインスタンスを提供する必要がある場合に、どの実装を使用するかを知らせるものです。
アノテーションが付いた関数は、次の情報を Hilt に提供します。
- 関数の戻り値の型で、その関数が提供するインターフェースのインスタンスを知らせます。
- 関数のパラメータで、提供する実装を知らせます。
Kotlin
interface AnalyticsService { fun analyticsMethods() } // Constructor-injected, because Hilt needs to know how to // provide instances of AnalyticsServiceImpl, too. class AnalyticsServiceImpl @Inject constructor( ... ) : AnalyticsService { ... } @Module @InstallIn(ActivityComponent::class) abstract class AnalyticsModule { @Binds abstract fun bindAnalyticsService( analyticsServiceImpl: AnalyticsServiceImpl ): AnalyticsService }
Java
public interface AnalyticsService { void analyticsMethods(); } // Constructor-injected, because Hilt needs to know how to // provide instances of AnalyticsServiceImpl, too. public class AnalyticsServiceImpl implements AnalyticsService { ... @Inject AnalyticsServiceImpl(...) { ... } } @Module @InstallIn(ActivityComponent.class) public abstract class AnalyticsModule { @Binds public abstract AnalyticsService bindAnalyticsService( AnalyticsServiceImpl analyticsServiceImpl ); }
Hilt モジュール AnalyticsModule
に @InstallIn(ActivityComponent.class)
というアノテーションが付いています。これは、依存関係を ExampleActivity
に注入させるためです。このアノテーションは、AnalyticsModule
内のすべての依存関係が、アプリのすべてのアクティビティ内で使用できることを意味します。
@Provides を使用してインスタンスを注入する
型のコンストラクタ インジェクションができないのはインターフェースだけではありません。自分で所有していないクラスも、外部ライブラリに含まれているため、コンストラクタ インジェクションができません(Retrofit、OkHttpClient
、Room データベースなど)。Builder パターンでインスタンスを作成する必要がある場合も同様です。
前の例で考えてみましょう。AnalyticsService
クラスを直接所有しない場合は、Hilt モジュール内に関数を作成し、その関数に @Provides
アノテーションを付けることにより、この型のインスタンスを提供できます。
アノテーション付きの関数は、次の情報を Hilt に提供します。
- 関数の戻り値の型で、その関数が提供する型のインスタンスを知らせます。
- 関数のパラメータは、対応する型の依存関係を知らせます。
- 関数の本体は、対応する型のインスタンスの提供方法を知らせます。Hilt は、その型のインスタンスを提供する必要があるたびに関数の本体を実行します。
Kotlin
@Module @InstallIn(ActivityComponent::class) object AnalyticsModule { @Provides fun provideAnalyticsService( // Potential dependencies of this type ): AnalyticsService { return Retrofit.Builder() .baseUrl("https://example.com") .build() .create(AnalyticsService::class.java) } }
Java
@Module @InstallIn(ActivityComponent.class) public class AnalyticsModule { @Provides public static AnalyticsService provideAnalyticsService( // Potential dependencies of this type ) { return new Retrofit.Builder() .baseUrl("https://example.com") .build() .create(AnalyticsService.class); } }
同じ型に複数のバインディングを提供する
依存関係として複数の実装を同じ型で提供する必要がある場合は、Hilt で複数のバインディングを用意する必要があります。修飾子を使用することで、同じ型に対して複数のバインディングを定義できます。
修飾子は、1 つの型に複数のバインディングが定義されている場合に、そのタイプの特定のバインディングを識別するために使用するアノテーションです。
具体的な例で考えてみましょう。AnalyticsService
の呼び出しをインターセプトする場合は、インターセプタが付いた OkHttpClient
オブジェクトを使用できます。他のサービスには、別の方法で呼び出しをインターセプトする必要があります。この場合、OkHttpClient
の異なる 2 つの実装の提供方法を Hilt に知らせる必要があります。
まず、@Binds
メソッドまたは @Provides
メソッドにアノテーションを付けるために使用する修飾子を定義します。
Kotlin
@Qualifier @Retention(AnnotationRetention.BINARY) annotation class AuthInterceptorOkHttpClient @Qualifier @Retention(AnnotationRetention.BINARY) annotation class OtherInterceptorOkHttpClient
Java
@Qualifier @Retention(RetentionPolicy.RUNTIME) private @interface AuthInterceptorOkHttpClient {} @Qualifier @Retention(RetentionPolicy.RUNTIME) private @interface OtherInterceptorOkHttpClient {}
次に、Hilt は各修飾子に対応する型のインスタンスの提供方法を把握する必要があります。この場合、@Provides
が付いた Hilt モジュールを使用できます。2 つのメソッドでは戻り値の型が同じですが、修飾子によって異なるバインディングとしてラベル付けされます。
Kotlin
@Module @InstallIn(SingletonComponent::class) object NetworkModule { @AuthInterceptorOkHttpClient @Provides fun provideAuthInterceptorOkHttpClient( authInterceptor: AuthInterceptor ): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(authInterceptor) .build() } @OtherInterceptorOkHttpClient @Provides fun provideOtherInterceptorOkHttpClient( otherInterceptor: OtherInterceptor ): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(otherInterceptor) .build() } }
Java
@Module @InstallIn(ActivityComponent.class) public class NetworkModule { @AuthInterceptorOkHttpClient @Provides public static OkHttpClient provideAuthInterceptorOkHttpClient( AuthInterceptor authInterceptor ) { return new OkHttpClient.Builder() .addInterceptor(authInterceptor) .build(); } @OtherInterceptorOkHttpClient @Provides public static OkHttpClient provideOtherInterceptorOkHttpClient( OtherInterceptor otherInterceptor ) { return new OkHttpClient.Builder() .addInterceptor(otherInterceptor) .build(); } }
対応する修飾子でフィールドまたはパラメータをアノテーションすることにより、必要とする特定の型を注入できます。
Kotlin
// As a dependency of another class. @Module @InstallIn(ActivityComponent::class) object AnalyticsModule { @Provides fun provideAnalyticsService( @AuthInterceptorOkHttpClient okHttpClient: OkHttpClient ): AnalyticsService { return Retrofit.Builder() .baseUrl("https://example.com") .client(okHttpClient) .build() .create(AnalyticsService::class.java) } } // As a dependency of a constructor-injected class. class ExampleServiceImpl @Inject constructor( @AuthInterceptorOkHttpClient private val okHttpClient: OkHttpClient ) : ... // At field injection. @AndroidEntryPoint class ExampleActivity: AppCompatActivity() { @AuthInterceptorOkHttpClient @Inject lateinit var okHttpClient: OkHttpClient }
Java
// As a dependency of another class. @Module @InstallIn(ActivityComponent.class) public class AnalyticsModule { @Provides public static AnalyticsService provideAnalyticsService( @AuthInterceptorOkHttpClient OkHttpClient okHttpClient ) { return new Retrofit.Builder() .baseUrl("https://example.com") .client(okHttpClient) .build() .create(AnalyticsService.class); } } // As a dependency of a constructor-injected class. public class ExampleServiceImpl ... { private final OkHttpClient okHttpClient; @Inject ExampleServiceImpl(@AuthInterceptorOkHttpClient OkHttpClient okHttpClient) { this.okHttpClient = okHttpClient; } } // At field injection. @AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { @AuthInterceptorOkHttpClient @Inject OkHttpClient okHttpClient; ... }
ベスト プラクティスとして、型に修飾子を追加する場合は、その依存関係を提供するすべての方法に対して修飾子を追加することをおすすめします。基本実装または共通実装に修飾子を付けないと、エラーが発生しやすくなり、Hilt が誤った依存関係を注入するかもしれません。
Hilt で事前定義されている修飾子
Hilt では、いくつかの修飾子が事前定義されています。たとえば、アプリケーションまたはアクティビティから Context
クラスが必要な場合のために、@ApplicationContext
修飾子と @ActivityContext
修飾子が用意されています。
例にある AnalyticsAdapter
クラスでアクティビティのコンテキストが必要であるとします。次のコードは、AnalyticsAdapter
にアクティビティのコンテキストの提供方法を示しています。
Kotlin
class AnalyticsAdapter @Inject constructor( @ActivityContext private val context: Context, private val service: AnalyticsService ) { ... }
Java
public class AnalyticsAdapter { private final Context context; private final AnalyticsService service; @Inject AnalyticsAdapter( @ActivityContext Context context, AnalyticsService service ) { this.context = context; this.service = service; } }
Hilt で利用できる他の事前定義済みバインディングについては、コンポーネントのデフォルトのバインディングをご覧ください。
Android クラスに対して生成されたコンポーネント
フィールド インジェクションができる Android クラスでは、それぞれのクラスごとに、@InstallIn
アノテーションで参照できる関連付けされた Hilt コンポーネントがあります。各 Hilt コンポーネントでは、対応する Android クラスにバインディングを注入する必要があります。
これまでの例では、Hilt モジュールでの ActivityComponent
の使用方法を示しました。
Hilt には次のコンポーネントが用意されています。
Hilt コンポーネント | インジェクションの対象 |
---|---|
SingletonComponent |
Application |
ActivityRetainedComponent |
なし |
ViewModelComponent |
ViewModel |
ActivityComponent |
Activity |
FragmentComponent |
Fragment |
ViewComponent |
View |
ViewWithFragmentComponent |
@WithFragmentBindings アノテーションが付いた View |
ServiceComponent |
Service |
コンポーネントのライフタイム
Hilt は、対応する Android クラスのライフサイクルに従って、生成されたコンポーネント クラスのインスタンスを自動的に作成、破棄します。
生成されたコンポーネント | 作成のタイミング | 破棄のタイミング |
---|---|---|
SingletonComponent |
Application#onCreate() |
Application を破棄しました |
ActivityRetainedComponent |
Activity#onCreate() |
Activity#onDestroy() |
ViewModelComponent |
ViewModel を作成しました |
ViewModel を破棄しました |
ActivityComponent |
Activity#onCreate() |
Activity#onDestroy() |
FragmentComponent |
Fragment#onAttach() |
Fragment#onDestroy() |
ViewComponent |
View#super() |
View を破棄しました |
ViewWithFragmentComponent |
View#super() |
View を破棄しました |
ServiceComponent |
Service#onCreate() |
Service#onDestroy() |
コンポーネントのスコープ
デフォルトでは、Hilt のすべてのバインディングはスコープ設定されていません。つまり、アプリがバインディングをリクエストするたびに、必要な型の新しいインスタンスが作成されます。
例では、Hilt が AnalyticsAdapter
を別の型の依存関係として提供するたびに、またはフィールド インジェクションを通じて(ExampleActivity
として)提供するたびに、AnalyticsAdapter
の新しいインスタンスが提供されます。
ただし、Hilt では、バインディングを特定のコンポーネントにスコープ設定することもできます。Hilt は、バインディングの対象となるコンポーネントのインスタンスごとに 1 回だけスコープ設定されたバインディングを作成します。そして、そのバインディングに対するすべてのリクエストで同じインスタンスを共有します。
次の表に、生成された各コンポーネントに対するスコープ アノテーションを示します。
Android クラス | 生成されたコンポーネント | スコープ |
---|---|---|
Application |
SingletonComponent |
@Singleton |
Activity |
ActivityRetainedComponent |
@ActivityRetainedScoped |
ViewModel |
ViewModelComponent |
@ViewModelScoped |
Activity |
ActivityComponent |
@ActivityScoped |
Fragment |
FragmentComponent |
@FragmentScoped |
View |
ViewComponent |
@ViewScoped |
@WithFragmentBindings アノテーションが付いた View |
ViewWithFragmentComponent |
@ViewScoped |
Service |
ServiceComponent |
@ServiceScoped |
例では、@ActivityScoped
を使用して AnalyticsAdapter
を ActivityComponent
にスコープ設定している場合、対応するアクティビティが存続する間、常に AnalyticsAdapter
の同じインスタンスが提供されます。
Kotlin
@ActivityScoped class AnalyticsAdapter @Inject constructor( private val service: AnalyticsService ) { ... }
Java
@ActivityScoped public class AnalyticsAdapter { private final AnalyticsService service; @Inject AnalyticsAdapter(AnalyticsService service) { this.service = service; } ... }
AnalyticsService
の内部状態が、ExampleActivity
の中だけでなくアプリ内のどの場所でも同じインスタンスを使用する必要があるとします。この場合、AnalyticsService
を SingletonComponent
にスコープ設定するのが適切です。こうすると、コンポーネントは、AnalyticsService
のインスタンスの提供が必要となるたびに、毎回同じインスタンスを提供するようになります。
次の例は、Hilt モジュール内のコンポーネントにバインディングをスコープ設定する方法を示しています。バインディングのスコープは、インストール先のコンポーネントのスコープと一致する必要があるため、この例では ActivityComponent
ではなく SingletonComponent
に AnalyticsService
をインストールする必要があります。
Kotlin
// If AnalyticsService is an interface. @Module @InstallIn(SingletonComponent::class) abstract class AnalyticsModule { @Singleton @Binds abstract fun bindAnalyticsService( analyticsServiceImpl: AnalyticsServiceImpl ): AnalyticsService } // If you don't own AnalyticsService. @Module @InstallIn(SingletonComponent::class) object AnalyticsModule { @Singleton @Provides fun provideAnalyticsService(): AnalyticsService { return Retrofit.Builder() .baseUrl("https://example.com") .build() .create(AnalyticsService::class.java) } }
Java
// If AnalyticsService is an interface. @Module @InstallIn(SingletonComponent.class) public abstract class AnalyticsModule { @Singleton @Binds public abstract AnalyticsService bindAnalyticsService( AnalyticsServiceImpl analyticsServiceImpl ); } // If you don't own AnalyticsService. @Module @InstallIn(SingletonComponent.class) public class AnalyticsModule { @Singleton @Provides public static AnalyticsService provideAnalyticsService() { return new Retrofit.Builder() .baseUrl("https://example.com") .build() .create(AnalyticsService.class); } }
Hilt コンポーネントのスコープについて詳しくは、Android と Hilt でのスコープ設定をご覧ください。
コンポーネント階層
モジュールをコンポーネントにインストールすると、コンポーネント内の他のバインディングの依存関係として、そのバインディングにアクセスできます。また、コンポーネント階層内で下位にある子コンポーネント内の他のバインディングの依存関係としてもアクセスできます。
コンポーネントのデフォルト バインディング
各 Hilt コンポーネントには、Hilt が独自のカスタム バインディングに依存関係として注入できるデフォルト バインディングのセットが用意されています。このバインディングは、特定のサブクラスではなく、一般のアクティビティ型とフラグメント型に対応しています。これは、Hilt では 1 つのアクティビティ コンポーネント定義を使用して、すべてのアクティビティを注入するためです。アクティビティごとに、このコンポーネントの異なるインスタンスがあります。
Android コンポーネント | デフォルト バインディング |
---|---|
SingletonComponent |
Application |
ActivityRetainedComponent |
Application |
ViewModelComponent |
SavedStateHandle |
ActivityComponent |
Application 、Activity |
FragmentComponent |
Application 、Activity 、Fragment |
ViewComponent |
Application 、Activity 、View |
ViewWithFragmentComponent |
Application 、Activity 、Fragment 、View |
ServiceComponent |
Application 、Service |
アプリケーション コンテキスト バインディングは @ApplicationContext
でも利用できます。次に例を示します。
Kotlin
class AnalyticsServiceImpl @Inject constructor( @ApplicationContext context: Context ) : AnalyticsService { ... } // The Application binding is available without qualifiers. class AnalyticsServiceImpl @Inject constructor( application: Application ) : AnalyticsService { ... }
Java
public class AnalyticsServiceImpl implements AnalyticsService { private final Context context; @Inject AnalyticsAdapter(@ApplicationContext Context context) { this.context = context; } } // The Application binding is available without qualifiers. public class AnalyticsServiceImpl implements AnalyticsService { private final Application application; @Inject AnalyticsAdapter(Application application) { this.application = application; } }
アクティビティ コンテキスト バインディングは @ActivityContext
でも利用できます。次に例を示します。
Kotlin
class AnalyticsAdapter @Inject constructor( @ActivityContext context: Context ) { ... } // The Activity binding is available without qualifiers. class AnalyticsAdapter @Inject constructor( activity: FragmentActivity ) { ... }
Java
public class AnalyticsAdapter { private final Context context; @Inject AnalyticsAdapter(@ActivityContext Context context) { this.context = context; } } // The Activity binding is available without qualifiers. public class AnalyticsAdapter { private final FragmentActivity activity; @Inject AnalyticsAdapter(FragmentActivity activity) { this.activity = activity; } }
Hilt でサポートされていないクラスに依存関係を注入する
Hilt では一般的な Android クラスのほとんどがサポートされています。Hilt でサポートされていないクラスには、フィールド インジェクションを行う必要があります。
そのような場合、@EntryPoint
アノテーションを使用してエントリ ポイントを作成します。エントリ ポイントは、Hilt が管理するコードとそうでないコードの境界であり、コード内で Hilt で管理するオブジェクトのグラフが開始される最初のポイントです。エントリ ポイントを使用すると、Hilt が管理しないコードを使用して、依存関係グラフ内の依存関係を提供することができます。
たとえば、コンテンツ プロバイダは Hilt で直接サポートされません。コンテンツ プロバイダが Hilt を使用して依存関係を取得するようにしたい場合は、必要なバインディング タイプごとに @EntryPoint
アノテーションが付いたインターフェースを定義し、修飾子を含める必要があります。さらに、次のように @InstallIn
を追加して、エントリ ポイントをインストールするコンポーネントを指定します。
Kotlin
class ExampleContentProvider : ContentProvider() { @EntryPoint @InstallIn(SingletonComponent::class) interface ExampleContentProviderEntryPoint { fun analyticsService(): AnalyticsService } ... }
Java
public class ExampleContentProvider extends ContentProvider { @EntryPoint @InstallIn(SingletonComponent.class) interface ExampleContentProviderEntryPoint { public AnalyticsService analyticsService(); } ... }
エントリ ポイントにアクセスするには、EntryPointAccessors
の適切な静的メソッドを使用します。パラメータは、コンポーネント インスタンスか、コンポーネント ホルダーとして機能する @AndroidEntryPoint
オブジェクトのいずれかです。パラメータとして渡すコンポーネントと EntryPointAccessors
静的メソッドの両方を、@EntryPoint
インターフェースの @InstallIn
アノテーションで指定した Android クラスと一致させてください。
Kotlin
class ExampleContentProvider: ContentProvider() { ... override fun query(...): Cursor { val appContext = context?.applicationContext ?: throw IllegalStateException() val hiltEntryPoint = EntryPointAccessors.fromApplication(appContext, ExampleContentProviderEntryPoint::class.java) val analyticsService = hiltEntryPoint.analyticsService() ... } }
Java
public class ExampleContentProvider extends ContentProvider { @Override public Cursor query(...) { Context appContext = getContext().getApplicationContext(); ExampleContentProviderEntryPoint hiltEntryPoint = EntryPointAccessors.fromApplication(appContext, ExampleContentProviderEntryPoint.class); AnalyticsService analyticsService = hiltEntryPoint.analyticsService(); } }
この例では、エントリ ポイントが SingletonComponent
にインストールされているため、ApplicationContext
を使用してエントリ ポイントを取得する必要があります。取得するバインディングが ActivityComponent
にある場合は、代わりに ActivityContext
を使用します。
Hilt と Dagger
Hilt は、Dagger 依存関係インジェクション ライブラリの上に構築されており、Dagger を Android アプリに組み込む標準的な方法を提供します。
Dagger に関連する Hilt の目標は次のとおりです。
- Android アプリを対象とした Dagger 関連のインフラストラクチャをシンプルなものにする。
- コンポーネントとスコープの標準セットを作成して、設定とアプリ間でのコード共有を容易し、リーダビリティを向上させる。
- テスト、デバッグ、リリースなど、さまざまなビルドタイプに対して異なるバインディングをプロビジョニングする簡単な方法を提供する。
Android オペレーティング システムは独自のフレームワーク クラスを数多くインスタンス化するため、Android アプリで Dagger を使用するには大量のボイラープレートを記述する必要があります。Hilt を使用すると、Android アプリで Dagger を使用するときに生じるボイラープレート コードを減らすことができます。Hilt では、次のものが自動的に生成され、提供されます。
- Dagger を使用して Android フレームワークのクラスを統合するためのコンポーネント(手動で作成する必要がなくなります)。
- Hilt が自動的に生成するコンポーネントで使用するスコープ アノテーション。
Application
やActivity
などの Android クラスを表す事前定義されたバインディング。@ApplicationContext
と@ActivityContext
を表す事前定義された修飾子。
Dagger コードと Hilt コードは、同じコードベース内で共存できます。ただし、ほとんどの場合、Android 上での Dagger の使用は、すべて Hilt で管理することをおすすめします。Dagger を使用するプロジェクトを Hilt に移行するには、移行ガイドと Dagger アプリを Hilt に移行する(Codelab)をご覧ください。
参考情報
Hilt の詳細については、次の参考リンクをご覧ください。