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フィードバックを取得できます。ローカル設定は不要です。