Hilt는 DI 라이브러리 중 하나로 기존에 존재하던 의존성 주입 라이브러리인 Dagger를 보다 쉽게 사용할 수 있도록 만든 도구입니다.
Hilt의 목표
- Android App을 위한 Dagger 관련 인프라 간소화
- 표준화 된 컴포넌트 세트와 스코프로 앱 간의 설정, 가독성 및 이해도, 코드 공유를 쉽게 만들기
- 앱 간의 설정, 가독성 및 코드 공유를 용이하게 하기 위한 표준 컴포넌트 및 스코프 생성
- 쉬운 방법으로 다양한 빌드 타입에 대해 다른 바인딩 제공
특징
- Dagger2 기반 라이브러리
- 표준화된 Dagger2 사용법 제시
- 보일러플레이트 코드 감소
- 프로젝트 설정 간소화
- 쉬운 모듈 탐색과 통합
- 개선된 테스트 환경
- Android Studio의 지원
- AndroidX 라이브러리의 호환
종속 항목 추가
build.gradle(project)
plugins {
...
id 'com.google.dagger.hilt.android' version '2.44' apply false
}
build.gradle(Module :app)
...
plugins {
id 'kotlin-kapt'
id 'com.google.dagger.hilt.android'
}
android {
...
}
dependencies {
implementation "com.google.dagger:hilt-android:2.44"
kapt "com.google.dagger:hilt-compiler:2.44"
}
// Allow references to generated code
kapt {
correctErrorTypes true
}
@HiltAndroidApp
Hilt를 사용하는 모든 App은 다음과 같은 어노테이션을 포함한 Application 클래스를 포함해야 한다.
@HiltAndroidApp
class MyApplication: Application() {...}
@AndroidEntryPoint
프로젝트의 각 클래스에 관한 개별 Hilt 컴포넌트를 생성한다.
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
@Inject lateinit var analytics: AnalyticsAdapter
...
}
Hilt에서 지원하는 클래스는 다음과 같다.
- Application - @HiltAndroidApp
- ViewModel - @HiltViewModel
- Activity
- Fragment
- View
- Service
- BroadcastReceiver
(Activity, Fragment 등은 @AndroidEntryPoint)
@AndroidEntryPoint 어노테이션을 사용한 클래스에 종속된 다른 클래스가 있다면 해당 클래스에도 어노테이션을 지정해주어야 한다.
Ex) BottomNavigation
- MainActiviy에서 BottomNavigation을 구현하여 Fragment를 연결시켰다면 MainActivity에 연결된 Fragment에도 모두 @AndroidEntryPoint 를 지정해줘야한다.
Ex) Intent
- Activity에서 Intent를 사용하여 다른 Activity로 넘겼을 때, 두 Activity에 @AndroidEntryPoint 를 지정해줘야한다.
@Inject
@Inject 어노테이션이 달린 변수에 대해 컴포넌트를 통한 의존성 주입 작업을 실행한다.
class ExampleAdapter @Inject constructor(
private val repository: Repository
) { ... }
모듈 생성
@Module
모듈은 @Module 어노테이션이 붙은 클래스를 모듈로 정의한다.
@InstallIn()
@Module 과 동반되어 사용되는 어노테이션으로 다음과 같이 사용된다.
@Module
@InstallIn(SingletonComponent::class)
object Module(...)
위의 예제에서 사용된 SingletonComponent와 같이 Hilt이 제공하는 표준화된 컴포넌트는 다음과 같다.
컴포넌트 및 생명주기
@AndroidEntryPoint는 해당 클래스에 맞는 Component를 지원
하위 컴포넌트는 상위 컴포넌트가 갖고 있는 의존성에 접근할 수 있지만, 상위 컴포넌트는 하위 컴포넌트가 갖고 있는 의존성에 접근할 수 없다.
만약 SingletonComponent로 모듈을 구성하였다면, 모든 컴포넌트에서 해당 모듈의 의존성에 대해 접근할 수 있다.
반대로 FragmentComponent로 모듈을 InstallIn 했다면 ActivityComponent에서는 해당 모듈의 의존성에 대해 접근할 수 없다.
@Provides
@Module
@InstallIn(SingletonComponent::class)
object Module {
@Singleton
@Provides
fun provideDatabase(
@ApplicationContext context: Context
): DataBase = DataBase.getInstance(context)
@Singleton
@Provides
fun provideAnalyticsService(): AnalyticsService {
return Retrofit.Builder()
.baseUrl("https://example.com")
.build()
.create(AnalyticsService::class.java)
}
}
다음과 같이 @Provides 어노테이션을 통해 제공할 인스턴스를 생성할 수 있다.
생성하면 @Inject를 통해 해당 인스턴스를 가져다 쓸 수 있다.
매개 변수에 context가 필요한 경우 @ApplicationContext로 context를 제공받을 수도 있습니다.
우리가 @Inject를 통해 의존성 주입을 요청할 때마다 Hilt는 필요한 유형의 새 인스턴스를 매번 생성한다.
이를 방지하기 위해 @Singleton 어노테이션을 사용하여 모든 요청은 하나의 인스턴스를 공유하게 된다.
주의사항은 주어진 Component에 맞는 어노테이션을 사용해야하며, 해당 예제에서는 SingletonComponent를 사용하였기 때문에 @Singleton 어노테이션을 사용해주었다.
종류는 다음과 같다.
그림으로 보는 Hilt
@HiltAndroidApp 을 지정
모듈 생성
@InstallIn(SingletonComponent::class)
@AndroidEntryPoint & @Inject
포스팅에 없는 내용 또는 자세한 내용은 안드로이드 공식문서를 참고 바랍니다.
'안드로이드 > DI' 카테고리의 다른 글
[안드로이드] Dependency Injection (DI) (0) | 2024.04.02 |
---|