Hilt vs Koin 의 비교도 했겠다. Hilt의 사용방법이나 구성 요소들에 대해 정리해보려 한다.
안드로이드 공식 문서의 내용을 기반으로 정리
1. Hilt란?
- Hilt는 프로젝트에서 의존성 주입을 실행하는 의존성 주입 라이브러리
- 프로젝트의 모든 Android 클래스에 컨테이너를 제공하고 수명 주기를 자동으로 관리하여 애플리케이션에서 DI를 사용하는 표준 방법을 제공한다.
- Dagger를 기반으로 빌드하여 컴파일 시간 정확성, 런타임 성능, 확장성의 이점을 누릴 수 있다.
1-1. 종속 항목 추가
프로젝트 build.gradle
plugins {
id("com.google.dagger.hilt.android") version "2.44" apply false
}
앱모듈 build.gradle
plugins {
id 'kotlin-kapt'
id("com.google.dagger.hilt.android")
}
dependencies {
implementation("com.google.dagger:hilt-android:2.44")
kapt("com.google.dagger:hilt-android-compiler:2.44")
}
kapt {
correctErrorTypes = true
}
1-2. 코드 세팅
@HiltAndroidApp
@HiltAndroidApp
class ExampleApplication : Application() { ... }
Hilt를 사용하는 모든 앱에서는 @HiltAndroidApp 이라는 어노테이션을 적은 Applicaiton Class를 작성해야 한다.
@HiltAndroidApp은 Hilt가 DI 그래프를 생성할 수 있도록 해준다.
@HiltAndroidApp이 Application의 생명주기를 참고해 컴파일 타임 시 필요한 클래스를 초기화 하고 의존성 객체를 제공해준다
@AndroidEntryPoint
Android 컴포넌트(Activit, Fragment, Service, View 등)에 의존성을 주입하기 위해서는 @AndroidEntryPoint를 반드시 사용해야 한다.
사용하지 않을 경우, Hilt는 주입을 수행하지 않고 컴파일 오류를 발생시킨다!!
컴포넌트 각각에 들어가야 할 어노테이션을 살펴보면 다음과 같다.
- Application -> @HiltAndroidApp
- ViewModel -> @HiltViewModel
- Activity -> @AndroidEntryPoint
- Fragment -> @AndroidEntryPoint
- View -> @AndroidEntryPoint
- Service -> @AndroidEntryPoint
- BroadcastReceiver -> @AndroidEntryPoint
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() { ... }
그래서 위의 코드와 같이 Hilt가 지원하는 Android 컴포넌트들에 적절한 Annotation을 넣어주면 된다.
@Inject
@Inject 어노테이션을 사용하여 인스턴스 제공하는 방법에 대해 Hilt에 대해 알려준다.
이때, 두 가지가 있는데
- Field Injection
- Constructor Injection
Field Injection
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
@Inject lateinit var analytics: AnalyticsAdapter
...
}
*참고
@Inject 시에 private 접근 제한자를 사용해서는 안된다.
Constructor Injection
class AnalyticsAdapter @Inject constructor(
private val service: AnalyticsService
) { ... }
1-3. Hilt 모듈
의존성 주입 방식에는 2가지의 경우가 있는데,
내가 구현한 클래스 -> Constructor Injection
인터페이스 or 추상 클래스 or 내가 구현하지 않은 클래스(3rd library) -> @Module
Constructor Injection은 위에서 봤으니까, @Moudle에 대해 정리해보겠다.
@Module
@Module은 Hilt에게 특정 유형의 인스턴스(인터페이스, 추상클래스, 외부 라이브러리)를 제공하는 방법을 알려준다.
또한 @Module 사용시 @InstallIn 주석을 지정해 각 모듈을 사용할 Android 클래스를 Hilt에 알려줘야 한다. -> Android 클래스에 대한 정리는 아래에
@Binds나 @Provides의 경우 의존성을 제공한는 메소드에 붙이게 되는데 아래와 같이 쓸 수 있다.
@Binds
- 추상 클래스나 인터페이스에서 사용한다.
- 반환 타입은 메소드가 제공할 인스턴스 타입, 메소드의 파라미터는 메소드가 제공할 구현체이다.
interface AnalyticsService {
fun analyticsMethods()
}
class AnalyticsServiceImpl @Inject constructor(
...
) : AnalyticsService { ... }
@Module
@InstallIn(ActivityComponent::class)
abstract class AnalyticsModule {
@Binds
abstract fun bindAnalyticsService(
analyticsServiceImpl: AnalyticsServiceImpl
): AnalyticsService
}
위의 코드처럼 @Binds 어노테이션으로 추상 메소드를 정의하고 analyticsServiceImpl이라는 구현체를 파라미터로 넣어줬다.
@Provides
- Hilt에 의존성을 주입하려는 인스턴스 클래스가 외부 라이브러리(OkHttp, Retrofit, DataStore)를 사용하는 경우,
- 빌더 패턴으로 인스턴스를 생성하는 경우 사용
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Singleton
@Provides
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
val apiKey = "http://123.12.1.1234:8080/"
return Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create()))
.baseUrl(apiKey)
.client(okHttpClient)
.build()
}
}
위의 코드에 경우 OkHttp를 넘겨줄 때 @Provides를 사용했다.
1-4. 인젝터 대상
Android 클래스마다 @InstallIn에 들어갈 수 있는 Hilt Component가 있다.
위의 코드에서 적었던 SingletonComponent은 앱 전체에서 사용되는 것! 각자 대상(범위)이 되는 구성요소가 존재한다.
1-5. 구성요소 생명주기
Component의 생명주기 동안 동일한 인스턴스를 제공해 줄 수 있다.
기본적으로 Hilt는 생명주기가 지정되지 않는다. 즉, 앱이 주입을 받기를 원할 때마다 Hilt에서는 필요한 유형의 새 인스턴스를 생성한다.
하지만 아래와 같이 범위를 지정해준다면, 그 범위 만큼 동일한 인스턴스를 사용할 수 있게 된다.
@ActivityScoped
class AnalyticsAdapter @Inject constructor(
private val service: AnalyticsService
) { ... }
위 코드에서 ActivityScoped를 주었기 때문에, 해당 Adapter가 쓰이는 Activity의 생명주기에 따라 동일한 인스턴스가 주어진다. 즉, Activity가 소멸하게 된다면 다른 인스턴스를 제공해주겠죠?
'Android > Android' 카테고리의 다른 글
[Android] Gradle (0) | 2024.07.15 |
---|---|
[Android] Jetpack이란? (0) | 2024.07.09 |
[Android] Intent(인텐트)란? (0) | 2024.05.27 |
[Android] DI - Hilt vs koin 비교 (1) (1) | 2024.05.09 |
[Android] 안드로이드 스레드 (0) | 2023.12.19 |