0Pricing
Android Academy · レッスン

Hiltによる依存性注入

Hiltで依存関係の管理を簡略化します。@HiltAndroidApp、@AndroidEntryPoint、@HiltViewModel、@Module、@Provides、@Singletonスコープの使い方を学びます。

「Hiltによる依存性注入」はCoddyKit上の無料Android Academyレッスンです。 これはレッスン6/6です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAndroid Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Android Academyコースには全6レッスンが含まれています。

Dependency Injectionとは

Dependency Injection(DI)とは、オブジェクト自身に依存関係を作成させるのではなく、必要なものを外部から提供する仕組みです。

DIを使わない場合、クラスが依存関係を自分で作成するため、結合が強くテストが困難になります。DIを使うと、依存関係を外部から注入できるため、疎結合になり、テストや置き換えが容易になります。

手動DIとHilt

手動DIは機能しますが、規模が大きくなると管理が大変になります。

// Manual DI — you create and pass everything:
val db = AppDatabase.getInstance(context)
val dao = db.userDao()
val repo = UserRepository(dao)
val factory = UserViewModel.Factory(repo)
val viewModel = ViewModelProvider(this, factory)[UserViewModel::class.java]

// With Hilt:
// Just annotate, Hilt does the wiring
@HiltViewModel
class UserViewModel @Inject constructor(private val repo: UserRepository) : ViewModel()

Hiltを追加する

プロジェクトにHiltを追加します。

// project/build.gradle:
buildscript {
    dependencies {
        classpath 'com.google.dagger:hilt-android-gradle-plugin:2.51'
    }
}

// app/build.gradle:
plugins {
    id 'com.google.dagger.hilt.android'
    id 'kotlin-kapt'
}

dependencies {
    implementation 'com.google.dagger:hilt-android:2.51'
    kapt 'com.google.dagger:hilt-android-compiler:2.51'
}

@HiltAndroidApp

Applicationクラスに@HiltAndroidAppのアノテーションを付けます。これはHiltのコンポーネント階層のエントリーポイントです。

@HiltAndroidApp
class MyApp : Application()

// Also register in AndroidManifest.xml:
// <application android:name=".MyApp" ...>

@AndroidEntryPoint

依存関係の注入が必要なActivity、Fragment、Serviceに@AndroidEntryPointを追加します。

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject lateinit var analytics: AnalyticsService

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        analytics.logEvent("app_open")
    }
}

@AndroidEntryPoint
class HomeFragment : Fragment() {
    // Fragment's parent Activity must also be @AndroidEntryPoint
}

@Inject — コンストラクタインジェクション

コンストラクタに@Injectを付けると、Hiltにクラスの作成方法を伝えられます。Hiltがすべてのパラメータを自動的に解決します。

class UserRepository @Inject constructor(
    private val userDao: UserDao,
    private val apiService: ApiService
) {
    suspend fun getUsers() = userDao.getAll()
    suspend fun syncFromNetwork() {
        val users = apiService.fetchUsers()
        userDao.insertAll(users)
    }
}

// Hilt sees UserRepository needs UserDao and ApiService,
// and automatically creates and injects them.

@HiltViewModel

ViewModelに@HiltViewModelのアノテーションを付け、@Inject constructorを使用します。Fragmentではby viewModels()で取得します。

@HiltViewModel
class UserViewModel @Inject constructor(
    private val repo: UserRepository
) : ViewModel() {

    val users = repo.getUsersFlow().asLiveData()
}

// In Fragment:
@AndroidEntryPoint
class UserFragment : Fragment() {
    private val viewModel: UserViewModel by viewModels()  // Hilt provides it
}

@Moduleと@Provides

コンストラクタインジェクションを使えない場合(インターフェースやサードパーティ製クラスなど)は、@Moduleを使ってインスタンスを提供します。

@Module
@InstallIn(SingletonComponent::class)   // lives for app lifetime
object NetworkModule {

    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    @Provides
    @Singleton
    fun provideApiService(retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }
}

@Binds — インターフェースのバインディング

@Bindsを使って、インターフェースに対して使用する実装をHiltに伝えます。

interface AnalyticsService {
    fun logEvent(name: String)
}

class FirebaseAnalytics @Inject constructor() : AnalyticsService {
    override fun logEvent(name: String) { /* Firebase impl */ }
}

@Module
@InstallIn(SingletonComponent::class)
abstract class AnalyticsModule {

    @Binds
    @Singleton
    abstract fun bindAnalytics(impl: FirebaseAnalytics): AnalyticsService
}

Hiltのスコープ

スコープは、注入されたインスタンスが存続する期間を制御します。

  • @Singleton — アプリの存続期間中、1つのインスタンスを使用します(ApplicationComponent)
  • @ActivityRetainedScoped — 構成変更後も存続します
  • @ActivityScoped — Activityごとに1つのインスタンスを使用します
  • @FragmentScoped — Fragmentごとに1つのインスタンスを使用します
  • @ViewModelScoped — ViewModelごとに1つのインスタンスを使用します

Hiltを使ったテスト

Hiltのテストサポートを使い、テストでは実際の依存関係を偽物に置き換えます。

@HiltAndroidTest
class UserRepositoryTest {

    @get:Rule
    val hiltRule = HiltAndroidRule(this)

    @Inject
    lateinit var repo: UserRepository

    @Before
    fun setUp() {
        hiltRule.inject()
    }

    @Test
    fun usersAreFetched() {
        assertNotNull(repo)
    }
}

理解度チェック

アプリ全体のDIコンポーネント階層を生成するようHiltに指示するアノテーションはどれですか?

まとめ:HiltによるDependency Injection

Hiltを使うと、AndroidでのDIをほぼ自動化できます。

  • Applicationクラスに@HiltAndroidAppを付けます
  • ActivityとFragmentに@AndroidEntryPointを付けます
  • 注入可能なクラスには@Inject constructorを使用します
  • ViewModelには@HiltViewModelと@Inject constructorを使用します
  • サードパーティ製クラスやインターフェースには@Moduleと@Providesを使用します
  • アプリ全体で1つのインスタンスを共有するには@Singletonを使用します

次は、Firebase Cloud Messagingを使ったプッシュ通知です。

よくある質問

「Hiltによる依存性注入」レッスンは無料ですか?

はい。「Hiltによる依存性注入」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Android Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Android Academyコースには全6レッスンが含まれています。

「Hiltによる依存性注入」で何を学びますか?

Hiltで依存関係の管理を簡略化します。@HiltAndroidApp、@AndroidEntryPoint、@HiltViewModel、@Module、@Provides、@Singletonスコープの使い方を学びます。 ブラウザで直接実行するハンズオンコードでAndroid Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Android Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAndroid Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン6/6です。

「Hiltによる依存性注入」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAndroid Academyレッスンでコードを書いて実行できますか?

はい。すべてのAndroid Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ViewModelとLiveData
  2. Room Database
  3. コルーチンとSuspend関数
  4. Repositoryパターン
  5. Navigation Component
  6. Hiltによる依存性注入
← Android Academyに戻る