0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Android】Hiltを導入する

Posted at

はじめに

この記事では、Android開発において用いられる依存性注入ライブラリのHiltについて自分の理解をまとめておきます。
初学者ですので、記事の内容には誤りが含まれる可能性がありますがコメントで指摘していただけると幸いです。

Hiltの公式ドキュメントはこちら↓
https://developer.android.com/training/dependency-injection/hilt-android?hl=ja

依存性注入(DI)の概要

依存性注入(Dependency Injection)とは、クラスが必要とするオブジェクトを外部から注入することでコードの柔軟性を向上させる手法です。
DIのメリットとして、コードが変更に強くなるという点が挙げられます。(この点については後ほど説明します。)

依存性の例

例として、UserViewModelというViewModelクラスがUserRepositoryというリポジトリクラスを利用してユーザー情報を取得するというケースを仮定します。

class UserRepositoryImpl {
    fun getUserName(): String {
        return "UserName"
    }
}
class UserViewModel : ViewModel() {
    // 直接UserRepositoryに依存している
    private val userRepositoryImpl = UserRepositoryImpl()

    fun fetchUserName(): String {
        return userRepositoryImpl.getUserName()
    }
}

直接依存がある状態のクラス図
このコードにおいては、UserViewModelの中でUserRepositoryImplクラスのインスタンスを生成しています。これがUserViewModelクラスが直接的にUserRepositoryImplクラスに依存している状態になります。この場合、UserRepositoryImplクラスが変更されるとき、UserViewModel側のコードも修正する必要が出てきます。
具体例としてリポジトリをRemoteUserRepositoryLocalUserRepositoryに分けたくなったときを考えると、以下のようにUserViewModelを修正する必要があります。

class UserViewModel : ViewModel() {
    private val userRepositoryImpl = RemoteUserRepository()

    fun fetchUserName(): String {
        return userRepositoryImpl.getUserName()
    }
}

ここで、この依存関係を外部から注入するように変更してみます。
まずはUserRepositoryというインタフェースを用意し、ここで宣言されたメソッドをUserRepositoryImplクラスで実装するという形に設計を変更します。

interface UserRepository{
    fun getUserName(): String
}
class UserRepositoryImpl : UserRepository{
    override fun getUserName(): String {
        return "UserName"
    }
}

そして、UserViewModelはインタフェースであるUserRepositoryに依存し、UserRepositoryImplの具体的な実装には依存しないようにします。

class UserViewModel(private val userRepository: UserRepository):ViewModel() {
    fun fetchUserName(): String {
        return userRepository.getUserName()
    }
}

上記のコードには、上で紹介したUserViewModelUserRepositoryImplに直接依存しているケースと比較して以下のような変更点があります。
依存関係を注入した状態のクラス図

DIのメリット

DIのメリットとしては実装の変更がしやすくなるということが挙げられます。例えば、UserRepositoryImplが以下のようなLocalUserRepositoryに変更されたとします。

class LocalUserRepository : UserRepository {
    override fun getUserName(): String {
        return "LocalUserName"
    }
}
実装クラス変更された状態のクラス図

このケースではインタフェースであるLocalUserRepositoryを実装するクラスが変更されますが、UserViewModel側ではUserRepositoryを引数として受け取るままでよく、コードに変更を加える必要性はありません。

Hiltの導入

それでは実際にHiltを使って依存関係を注入していきます。
まずProjectレベルのbuild.gradleに以下の内容を追加します。

build.gradle.kts(Project)
plugins {
    ・・・
    id("com.google.dagger.hilt.android") version "2.51.1" apply false
}

また、Moduleレベルのbuild.gradleに以下の内容を追加します。

build.gradle.kts(Module)
plugins {
    id("kotlin-kapt")
    id("com.google.dagger.hilt.android")
}
・・・
dependencies{
    ・・・
    implementation("com.google.dagger:hilt-android:2.51.1")
    kapt("com.google.dagger:hilt-android-compiler:2.51.1")
}

次にApplicationクラスに@HiltAndroidAppというアノテーションを付与します。
Applicationクラスを作っていない場合は、以下のように空でよいのでApplicationクラスを作成します。

@HiltAndroidApp
class SampleApplication : Application()

ここからは上の例で挙げている、「UserViewModelクラスがUserRepositoryインタフェースに依存し、その実装をUserRepositoryImplが行っている」という例を用いて説明していきます。
依存関係の注入を行うためには、UserRepositoryのインスタンスをUserViewModelに渡すとき、そのUserRepositoryの具体的な実装(どのインスタンスを渡せばよいのか)をHiltに伝える必要があります。

今回はUserRepositoryの依存関係をModule.ktというファイルに記述することにします。

Module.kt
@Module
@InstallIn(SingletonComponent::class)
object Module{
    @Provides
    @Singleton
    fun provideUserRepository(): UserRepository {
        return UserRepositoryImpl() // 実際の実装クラスを返す
    }
}

@ModuleはHilt に依存関係の提供方法を教えるためのクラスであることを示します。
@InstallIn(singletonComponent::class)はモジュールがアプリ全体(SingletonComponent)に適用されることを意味します。
また、@ProvidesprovideUserRepository関数が具体的な実装方法を提供するメソッドであることを示しています。さらに@Singletonは提供される UserRepository のインスタンスがアプリ全体で1つだけ存在するようにすることを保証するものです。

次にActivityクラスに@AndroidEntryPointアノテーションを付与します。依存関係の注入を行うには注入を行いたいクラスとその上位のコンポーネントにアノテーションを付与する必要があるためです。

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

そしてUserViewModelクラスに@HiltViewModelアノテーションを付与、さらにコンストラクタに @Inject を付与します。

@HiltViewModel
class UserViewModel @Inject constructor(
    private val userRepository: UserRepository
) : ViewModel() {
    ・・・
}

これにより、Hilt が UserRepository の依存関係を解決し、UserViewModel に注入することができます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?