티스토리 뷰
Hilt는 안드로이드 스튜디오에서 편리하게 DI를 사용할 수 있도록 Dagger 기반으로 빌드된 라이브러리이다.
프로젝트의 모든 Android 클래스에 컨테이너를 제공하고, 수명 주기를 자동으로 관리하여 DI를 사용한다.
1. build.gradle (kts 기준)
프로젝트 수준
plugins {
id("com.google.dagger.hilt.android") version "2.48" apply false
}
모듈 수준
plugins {
id("kotlin-kapt")
id("dagger.hilt.android.plugin")
}
dependencies {
implementation ("com.google.dagger:hilt-android:2.48")
kapt ("com.google.dagger:hilt-android-compiler:2.48")
}
kapt {
generateStubs = true
}
코틀린 1.9.0 버전에 맞는 Hilt 버전은 2.48이다.
사용하는 코틀린 버전에 맞게 라이브러리 버전을 선택한다.
2. 애플리케이션 설정
@HiltAndroidApp
class MyApplication : Application() {
...
}
Hilt로 의존성 주입을 하기 위해서는 가장 먼저 Application 클래스에 @HiltAndroidApp 어노테이션을 추가한다.
Hilt가 Application 수명 주기에 연결되어 이와 관련한 의존성을 제공한다.
Application은 앱의 가장 상위 구성요소이므로 다른 구성요소는 이 Application에서 제공하는 의존성을 사용할 수 있다.
3. 안드로이드 클래스
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var analytics: AnalyticsAdapter
...
}
Hilt가 제공하는 안드로이드 구성요소에 @AndroidEntryPoint을 붙인다.
위 어노테이션을 붙임으로써 클래스의 생명주기에 따라 자동으로 Hilt 요소로 인스턴스화되어 의존성 주입이 처리된다.
의존성을 주입받기를 원하는 객체 앞에 @Inject를 붙이면, Hilt가 알아서 의존성 주입을 해준다.
코드로 인스턴스를 따로 생성해서 프로퍼티로 저장해두지 않아도 된다.
* @Inject 어노테이션이 붙은 프로퍼티는 private일 수 없고, lateinit var으로 지정해주어야 한다.
Hilt가 지원하는 안드로이드 클래스
- Application (@HiltAndroidApp)
- ViewModel (@HiltViewModel)
- Activity
- Fragment
- View
- Service
- BroadcastReceiver
4. 클래스의 생성자
앞에서 @Inject로 의존성 주입 받기를 원하는 객체를 지정했다.
그러기 위해서는 Hilt가 인스턴스를 생성하기 위한 정보를 알아야 한다.
class AnalyticsAdapter @Inject constructor(
private val service: AnalyticsService
) {
...
}
Hilt에게 정보를 제공하기 위해서 생성자 주입을 사용한다.
위 코드와 같이 클래스의 생성자에 @Inject 어노테이션을 사용하여 인스턴스를 생성할 정보를 제공한다.
class AnalyticsService @Inject constructor(
@ApplicationContext context: Context
) {
...
}
생성자의 매개변수로 AnalyticsService가 들어오므로 Hilt에게 AnalyticsService의 정보도 알아야 한다.
만약 이 클래스의 생성자로 context가 필요한 경우, @ApplicationContext나 @ActivityContext를 사용해 context를 제공한다.
@ApplicationContext는 말그대로 앱의 context가 주입되고,
@ActivityContext는 이 클래스를 주입받기를 원하는 액티비티의 context가 주입된다.
5. Hilt가 인스턴스 생성 정보를 알지 못하는 경우
외부 라이브러리나 인터페이스인 경우, Hilt가 객체를 찾을 수 없어서 일반적인 방법으로 의존성 주입이 불가능하다.
이때 @Module과 @InstallIn 어노테이션을 지정하여 Hilt에게 의존성 주입 정보를 제공해야 한다.
@Module을 통해 특정 유형의 인스턴스를 제공하는 방법을 알려주고,
@InstallIn을 통해 각 모듈을 사용하거나 설치할 클래스를 알려준다.
5-1. 외부 라이브러리 객체 주입
클래스가 외부 라이브러리에서 제공되기 때문에 클래스 파일이 현재 프로젝트에 존재하지 않는 경우,
Hilt가 인스턴스를 생성할 수 없다. (ex: Retrofit, OkHttpClient, Room의 Database)
@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {
@Provides
fun provideAnalyticsService(
...
): AnalyticsService {
return Retrofit.Builder()
.baseUrl("https://example.com")
.build()
.create(AnalyticsService::class.java)
}
}
@Module 클래스 내에 @Provides로 지정된 함수를 생성한다.
함수 내부에 인스턴스를 생성하는 코드를 작성하여 Hilt에게 인스턴스를 제공하는 방법을 알려준다.
5-2. 인터페이스의 구현체 주입
만약 어떤 액티비티에서 AnalyticsService 타입의 인스턴스를 주입받기를 원하는데,
AnalyticsService가 인터페이스라면 Hilt는 인스턴스를 생성할 수 없을 것이다.
interface AnalyticsService {
fun analyticsMethods()
}
class AnalyticsServiceImpl @Inject constructor(
...
) : AnalyticsService {
...
}
@Module
@InstallIn(ActivityComponent::class)
abstract class AnalyticsModule {
@Binds
abstract fun bindAnalyticsService(
analyticsServiceImpl: AnalyticsServiceImpl
): AnalyticsService
}
대신 @Module로 지정된 abstract 클래스 내에 @Binds로 지정된 abstract 함수를 생성하고,
그 함수의 매개변수로 인터페이스 구현체 클래스가 어떤 것인지 지정해야 한다.
또한 함수의 리턴타입은 인터페이스를 구현한 클래스가 아닌 인터페이스로 지정한다.
이 경우 무조건 클래스와 함수가 abstract여야 한다.
여기서 @InstallIn(ActivityComponent::class)인 이유는, 이 인스턴스를 액티비티에 주입해야 하기 때문이다.
6. @InstallIn
@InstallIn 어노테이션의 파라미터로 의존성을 주입받을 대상을 지정할 수 있다.
예시 코드에서는 ActivityComponent::class만 사용했는데,
아래와 같이 의존성 주입 대상에 따라 여러 파라미터를 사용할 수 있다.
@InstallIn 인자 | 의존성 주입 대상 |
SingletonComponent | Application |
ActivityRetainedComponent | N/A |
ViewModelComponent | ViewModel |
ActivityComponent | Activity |
FragmentComponent | Fragment |
ViewComponent | View |
ViewWithFragmentComponent | @WithFragmentBingings 지정된 View |
ServiceComponent | Service |
'android' 카테고리의 다른 글
[안드로이드/코틀린] 특정 뷰가 화면에서 가려지는지 여부를 동적으로 확인하기 (1) | 2024.01.28 |
---|---|
[안드로이드/오류] Failed to compile values file. Resource compilation failed. Check logs for details. (1) | 2024.01.18 |
[안드로이드/코틀린] BottomNavigationView 커스텀 (1) | 2023.10.25 |
[안드로이드/코틀린] Navigation 구현하기 (1) | 2023.10.25 |
[안드로이드/코틀린] FCM를 이용하여 사용자 별로 Notification 보내기-2 (0) | 2023.10.16 |