# Android依存性注入:Hilt vs Koin 完全ガイドと面接質問集 2026 > HiltとKoinの違いをコード例・パフォーマンスベンチマーク・面接頻出質問で徹底比較。Hilt 2.57、Koin 4.2対応の2026年最新ガイド。 - Published: 2026-05-24 - Updated: 2026-05-24 - Author: SharpSkill - Tags: android, hilt, koin, dependency-injection, interview - Reading time: 10 min --- Androidアプリケーション開発において、依存性注入(DI)はクラス間の結合度を下げ、テスト容易性を高めるための基本的な設計手法である。2026年現在、Androidエコシステムを支配するDIフレームワークは2つ存在する。Googleが公式に推奨するコンパイル時ソリューション[Hilt](https://dagger.dev/hilt/)(バージョン2.57.1、Dagger上に構築)と、軽量なランタイムサービスロケーターである[Koin](https://insert-koin.io/)(バージョン4.2.1)である。どちらを選択するかは、ビルド時間、起動パフォーマンス、テスタビリティ、そしてチームのオンボーディング速度に直接影響する。 > **コンパイル時DI vs ランタイムDI** > > Hiltはコンパイル時に依存関係グラフ全体を検証し、バインディングが不足している場合はビルドを失敗させる。KoinはKotlin DSLを使用してランタイムに依存関係を解決するため、設定エラーは該当するコードパスが実行された時点で初めて検出される。この根本的な違いが、2つのフレームワーク間のすべてのトレードオフを決定づけている。 ## Hiltの内部動作メカニズム HiltはAndroidのライフサイクルクラスにマッピングされたDaggerコンポーネントを生成する仕組みである。`@HiltAndroidApp`アノテーションがコンパイル時にコード生成をトリガーし、宣言されたすべてのバインディングに対してファクトリーとプロバイダーを生成する。Hilt 2.48以降、推奨されるアノテーションプロセッサとしてKSP(Kotlin Symbol Processing)がKAPTに取って代わり、アノテーション処理時間をおよそ半分に短縮した。 典型的なHiltのセットアップは、バインディングを宣言するモジュール、エントリポイント(Activity、Fragment、またはViewModel)、そして`@HiltAndroidApp`でアノテーションされたApplicationクラスの3つの要素で構成される。 ```kotlin // AppModule.kt @Module @InstallIn(SingletonComponent::class) object AppModule { @Provides @Singleton fun provideRetrofit(): Retrofit { return Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build() } @Provides @Singleton fun provideUserRepository( retrofit: Retrofit ): UserRepository { return UserRepositoryImpl(retrofit.create(UserApi::class.java)) } } ``` ```kotlin // UserViewModel.kt @HiltViewModel class UserViewModel @Inject constructor( private val userRepository: UserRepository ) : ViewModel() { private val _users = MutableStateFlow>(emptyList()) val users: StateFlow> = _users.asStateFlow() fun loadUsers() { viewModelScope.launch { _users.value = userRepository.getUsers() } } } ``` コンパイラは、アプリが実行される前に`UserRepository`に有効なプロバイダーが存在するかどうかを検証する。バインディングの欠落はランタイムクラッシュではなく、ビルドエラーとして表面化する。 ## KoinのセットアップとKotlin DSLアプローチ KoinはHiltとは正反対のアプローチを採用している。コード生成もアノテーション処理も一切行わない。依存関係はKotlinのDSLを使用してプレーンなKotlinで宣言され、フレームワークはグローバルサービスレジストリを通じてランタイムに解決を行う。Koin 4.2では、起動時の並列読み込みを実現するレイジーモジュールと、スコープ解決を最適化する新しい`CoreResolverV2`エンジンが導入された。 ```kotlin // AppModule.kt val appModule = module { // Singleton Retrofit instance single { Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build() } // Singleton repository bound to its interface single { UserRepositoryImpl(get().create(UserApi::class.java)) } // ViewModel with injected repository viewModel { UserViewModel(get()) } } ``` ```kotlin // MyApplication.kt class MyApplication : Application() { override fun onCreate() { super.onCreate() startKoin { androidContext(this@MyApplication) modules(appModule) } } } ``` DSLは自然に読めるコードを提供し、Gradle設定にアノテーション処理プラグインを追加する必要がない。トレードオフとして、`get()`解決のタイポは、該当する注入ポイントが実行されたランタイム時にのみ表面化する。 ## パフォーマンスベンチマーク:ビルド時間 vs ランタイムコスト パフォーマンスに関する質問は、ほぼすべての[Android面接](/technologies/android/interview-questions/android-dependency-injection)で取り上げられる。具体的な数値が意見よりも重要である。 | 指標 | Hilt 2.57 (KSP) | Koin 4.2 | |--------|-----------------|----------| | クリーンビルドのオーバーヘッド | +8-15秒(KSPコード生成) | 約0秒(コード生成なし) | | インクリメンタルビルドのオーバーヘッド | +2-4秒 | 約0秒 | | アプリ起動(50バインディング) | 約0ms(事前生成コード) | 約5-15ms(グラフ解決) | | アプリ起動(500バインディング) | 約0ms | 約30-80ms | | APKサイズへの影響 | +200-400 KB(生成コード) | +100 KB(ランタイムライブラリ) | | バインディング欠落の検出 | コンパイルエラー | ランタイムクラッシュ | 100バインディング未満のプロジェクトでは、Koinのランタイムオーバーヘッドは体感できないレベルにとどまる。300バインディングを超えると起動コストが計測可能になるが、Koin 4.2のレイジーモジュールがモジュール読み込みの並列化によってこの問題を軽減している。 > **KSP vs KAPT** > > Hilt処理をKAPTからKSPに切り替えると、アノテーション処理時間が40-60%短縮される。KAPTでHiltを使用しているプロジェクトは、直ちにKSPへの移行を行うべきである。HiltはバージョンⅡ.48以降でKSPをサポートしている。 ## 各フレームワークでのテスト戦略 テスタビリティは、アーキテクチャの違いが実務的に顕著になる領域である。Hiltは`@TestInstallIn`を提供し、コンパイル時にプロダクションモジュールをテストダブルに差し替えることができる。Koinは`loadKoinModules()`を提供し、ランタイムで定義をオーバーライドする。 ```kotlin // Hilt test module — replaces AppModule bindings in tests @Module @TestInstallIn( components = [SingletonComponent::class], replaces = [AppModule::class] ) object FakeAppModule { @Provides @Singleton fun provideUserRepository(): UserRepository { return FakeUserRepository() // In-memory test double } } ``` ```kotlin // Koin test — override at runtime class UserViewModelTest : KoinTest { @Before fun setUp() { startKoin { modules( module { single { FakeUserRepository() } viewModel { UserViewModel(get()) } } ) } } @Test fun `loads users from repository`() { val viewModel: UserViewModel = get() viewModel.loadUsers() assertEquals(3, viewModel.users.value.size) } @After fun tearDown() { stopKoin() } } ``` Hiltのテストは、設定が誤ったテストモジュールをコンパイル時に検出する。Koinのテストは慎重なライフサイクル管理(`startKoin`/`stopKoin`)が必要だが、部分的なモジュールオーバーライドにおいてより高い柔軟性を提供する。 ## マルチモジュールアーキテクチャ:機能間でのDIスケーリング 大規模なAndroidプロジェクトでは、機能をGradleモジュールに分割するのが一般的である。DIフレームワークはモジュール境界をクリーンにサポートする必要がある。 Hiltでは、各機能モジュールが`@InstallIn`でアノテーションされた独自の`@Module`を宣言する。Hiltはコンパイル時にすべてのモジュールを単一のコンポーネント階層にマージする。[MVVMアーキテクチャ](/blog/android/mvvm-vs-mvi-architecture)はHiltのスコープ付きコンポーネントと自然に組み合わせることができる。 ```kotlin // feature-payments/PaymentModule.kt @Module @InstallIn(ViewModelComponent::class) object PaymentModule { @Provides fun providePaymentGateway( retrofit: Retrofit // Provided by :app module ): PaymentGateway { return StripePaymentGateway(retrofit.create(PaymentApi::class.java)) } } ``` Koinでは、機能モジュールが`module {}`宣言をエクスポートし、アプリモジュールが起動時にすべてを読み込む。Koin 4.2のレイジーモジュールにより、機能モジュールの読み込みを初回アクセスまで遅延させることが可能になった。 ```kotlin // feature-payments/paymentModule.kt val paymentModule = module { factory { StripePaymentGateway(get().create(PaymentApi::class.java)) } } // app/MyApplication.kt — loads all feature modules startKoin { modules(appModule, paymentModule, analyticsModule) } ``` Hiltはコンポーネントスコープによって依存関係の可視性を強制する。Koinは慣例に依存しており、任意のモジュールが他のモジュールの定義にアクセスできるため、柔軟性は高いが暗黙的な結合が生じる可能性がある。 ## Kotlin Multiplatformへの対応 Koinは[Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html)(KMP)をネイティブにサポートしている。同じ`module {}`DSLがAndroid、iOS、Desktop、Webターゲットで動作する。HiltはAndroid専用であり、Android固有のライフサイクルコンポーネントとDaggerアノテーションプロセッサに依存している。 複数のプラットフォームをターゲットとするプロジェクトにおいて、HiltとKoinの2つの選択肢の中ではKoinが唯一の実行可能なオプションとなる。共有ビジネスロジックモジュールで依存関係を一度宣言すれば、すべてのターゲットに注入できる。 ## Android DIに関する頻出面接質問 これらの質問は[Android技術面接](/technologies/android)で定期的に出題される。各回答は簡潔にまとめ、面接官が期待するポイントに焦点を当てている。 **Q: コンパイル時依存性注入とランタイム依存性注入の違いは何ですか?** コンパイル時DI(Hilt/Dagger)はビルド中にインジェクションコードを生成する。コンパイラが依存関係グラフ全体を検証し、バインディングの欠落をランタイム前に検出する。ランタイムDI(Koin)はサービスレジストリパターンを使用して、依存関係が初めて要求された時点で解決する。コンパイル時DIは起動が高速だがビルドが遅く、ランタイムDIはビルドオーバーヘッドがゼロだがエラー検出が遅延する。 **Q: Hiltのコンポーネントスコープにはどのようなものがあり、Androidのライフサイクルとどう対応していますか?** `SingletonComponent`はアプリケーション全体の存続期間中存在する。`ActivityRetainedComponent`は構成変更を越えて生存する。`ViewModelComponent`はViewModelのライフサイクルにスコープされる。`ActivityComponent`、`FragmentComponent`、`ViewComponent`はそれぞれ対応するAndroidライフサイクルオーナーに従う。カスタムスコープでこの階層を拡張することも可能である。 **Q: KoinはJetpack ComposeでのViewModel注入をどのように処理しますか?** Koinは、最も近い`ViewModelStoreOwner`にスコープされたViewModelを作成または取得するComposable関数として`koinViewModel()`を提供している。Koin 4.2以降、[Jetpack Composeナビゲーション](/blog/android/jetpack-compose-interview-questions)使用時にViewModelをナビゲーショングラフエントリにスコープする`koinNavViewModel()`が利用可能になった。 **Q: HiltよりもKoinが適切な選択となるのはどのような場合ですか?** KoinはKMPプロジェクト(HiltはAndroid専用)、ビルド時間が起動時間よりも重要な中小規模アプリ、アノテーション駆動の設定よりも明示的なKotlin DSLを好むチームに適している。プロトタイピングやPoC(概念実証)プロジェクトもKoinの最小限のセットアップから恩恵を受ける。 > **面接でよくある間違い** > > Koinを「依存性注入フレームワーク」と呼ぶのは、技術的に不正確である。Koinはサービスロケーターであり、依存関係はコンストラクタインジェクションによってプッシュされるのではなく、`get()`を介してプルされる。この区別に精通した面接官は、候補者がこの点を認識していることを期待する。Hilt/Daggerは生成されたコンストラクタ呼び出しを通じて真の依存性注入を実行する。 ## 判断フレームワーク:HiltとKoinの選択基準 | 要素 | Hilt | Koin | |--------|------|------| | グラフ検証 | コンパイル時 | ランタイム | | ビルド時間への影響 | 大(KSPコード生成) | なし | | 起動コスト | ほぼゼロ | グラフサイズに比例 | | 学習曲線 | 急(Daggerの概念) | 緩やか(純粋なKotlin DSL) | | KMPサポート | なし | あり | | Jetpack統合 | 深い(Google公式) | 良好(コミュニティ) | | チームスケーラビリティ | 強い(強制されたスコープ) | 柔軟(慣例ベース) | | テスト | `@TestInstallIn`(コンパイル安全) | `loadKoinModules`(ランタイム) | どちらのフレームワークも普遍的に優れているわけではない。選択はプロジェクトの規模、チームの経験、プラットフォームターゲットに依存する。 ## まとめ - Hilt 2.57とKSPの組み合わせは、コンパイル時のグラフ検証とほぼゼロの起動コストを実現し、厳格な信頼性要件を持つ大規模な単一プラットフォームAndroidプロジェクトにおいて有力な選択肢となる - Koin 4.2はレイジーモジュールと`CoreResolverV2`により起動パフォーマンスのギャップを縮小しつつ、ゼロビルドオーバーヘッドと完全なKMP互換性を維持している - 両フレームワークともマルチモジュールアーキテクチャに対応しているが、Hiltはコンパイル時にスコープ境界を強制する一方、Koinはチームの慣例に依存する - [Android面接対策](/technologies/android)において、コンパイル時とランタイムのトレードオフを理解し、各フレームワークが適するケースを明確に説明できることが期待される基準となる - フレームワーク間の移行は容易ではないため、初期の選択はプロジェクトの長期的なプラットフォーム戦略とスケーリングの方向性を考慮すべきである --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/ja/blog/android/android-dependency-injection-hilt-vs-koin