[Android] hilt 정리
Hilt란?
- 의존성 주입을 보다 편 하게 구현할 수 있도록 도와주는 라이브러리다.
- Android에 컴포넌트에 맞는 컨테이너 및 생명주기를 자동으로 관리
- dagger를 기반으로 빌드됨
의존성 추가
buildscript {
dependencies {
classpath("androidx.navigation:navigation-safe-args-gradle-plugin:${libs.versions.androidxNavigation.get()}")
}
}
plugins {
...
alias(libs.plugins.hilt) apply false
}
plugins {
kotlin("kapt")
id("com.google.dagger.hilt.android")
}
android {
...
}
dependencies {
implementation("com.google.dagger:hilt-android:2.44")
kapt("com.google.dagger:hilt-android-compiler:2.44")
}
// Allow references to generated code
kapt {
correctErrorTypes = true
}
Hilt 애플리케이션 클래스
-
Application에
@HiltAndroidApp
어노테이션을 포함해야함@HiltAndroidApp class ExampleApplication : Application() { ... }
- 애플리케이션 수준의 컨테이너 및 Hilt의 코드 생성을 트리거 함
- 해당 애플리케이션 객체의 생명 주기에 연결되어 관련 의존 항목을 제공함
Android 클래스에 의존성 주입
@AndroidEntryPoint
어노테이션을 통해 Android 클래스에 의존성을 주입할 수 있습니다.(Hilt 구성요소를 생성)- Application은
@HiltAndroidApp
을 통해서, ViewModel은@HiltViewModel
을 사용해야 함-
지원 항목
Application ViewModel Activity with ComponentActivity Extands Fragment with androidx.fragment Extands View Service BroadcastReceiver
-
-
구성요소에서 의존클래스를 주입받으려면
@Inject
를 통해 실행@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { @Inject lateinit var analytics: AnalyticsAdapter ... }
의존성 주입을 위한 구성요소 제공
- 의존성을 주입하기 위해서는 Hilt가 해당 클래스가 필요로하는 종속 항목의 인스턴스를 제공하는 방법을 알아야 함
- ex)
class Programmer(private val computer: Computer)
를 주입 하기 위해서는 computer 에 대한 정보가 필요
- ex)
- 해당 정보를 제공하는 방법은
@inject
어노테이션이 지정된 생성자의 매개변수가 해당 클래스의 종속 항목임을 Hilt에 알려줄 수 있음.class Programmer @inject constructor(private val computer: Computer)
- 위의 경우 computer의 인스턴스를 제공하는 방법도 알아야함.
Hilt 모듈
@Module
어노테이션이 지정된 클래스- 왜 필요한지?
- 제공 타입에 따라 생성자에서 생성자에서 의존성 주입을 할 수 없을 때가 있을 수도 있다.
- interface - 실제 구현체를 알 수 없음
- 외부 라이브러리의 클래스
- 위와 같은 상황에 module을 이용해 힐트에게 제공하는 타입에 해당하는 인스턴스 정보를 알려줄 수 있다.
- 제공 타입에 따라 생성자에서 생성자에서 의존성 주입을 할 수 없을 때가 있을 수도 있다.
@installIn
어노테이션을 지정해서 모듈을 사용하거나 설치할 Android 컴포넌트에게 알려야한다.
@Binds 를 이용한 인터페이스 인스턴스 주입
- Interface의 실제 어떤 인스턴스를 제공하는지 Hilt에게 알려준다.
- Module내에서
@Binds
어노테이션을 붙인 추상 함수를통해 해당 정보를 제공한다.- 매개 변수를 통해 실제 주입할 구현체를 Hilt에게 알려준다.
- 리턴 타입은 어떤 타입을 주입할지 Hilt에게 알려준다.
interface Computer{ fun on() } class IntelComputer @Inject constructor( ... ) : Computer{ ... } @Module @InstallIn(ActivityComponent::class) abstract class IntelModule { @Binds abstract fun bindIntelComputer( IntelComputer : IntelComputer ) : Computer }
@Provides를 이용한 인터페이스 인스턴스 주입
- interface 뿐만 아니라 외부 클래스에서 제공하는 클래스를 소유하지 않은 경우에도 유형을 제공할 수 없는 경우가 있다.
- 빌더 패턴을 통해 인스턴스를 만드는 경우와 같이 예를들어 Retrofit, OkHttpClinet, Room 등이 있다.
- Module내에서
@Provides
어노테이션을 붙인 함수를 통해 해당 인스턴스에 대한 정보를 제공- 매개변수는 해당 유형의 의존 항목을 Hilt에게 알려준다.
- 리턴 타입은 실제 주입할 구현체를 Hilt에게 알려준다.
- 함수의 본문에서는 해당 유형의 인스턴스를 제공하는 방법을 Hilt에게 알려준다.
- 해당 유형의 인스턴스를 제공해야 할 때마다 함수 본문을 실행함.
@Module @InstallIn(ActivityComponent::class) object IntelModule { @Provides fun provideIntelComputer( ...//intelComputer의 생성자에 필요한 매개변수 ) : IntelComputer { return IntelComputer(...) } }
@Qualifier를 통한 동일한 타입에 대한 여러 인스턴스 제공
- 주입하고자 하는 타입이 동일하지만 구현체를 달리하는 경우에 사용된다.
- Hilt에는 기본적으로 제공하는 한정자 어노테이션이 있다.
@ApplicationContext
@ActivityContext
@Qualifer
,@Retention
어노테이션을 통해 한정자 어노테이션을 만들 수있다.@Binds
,@Provides
메서드와 한정자 어노테이션을 통해 어떤 인스턴스를 제공할 지 Hilt에게 알려줄 수 있다.- 아래는 동일한 부모클래스를 갖지만 구현체가 다른 computer를 통해 각기 다른 인스턴스(Programmer)를 제공합니다.
@Qualifer @Retention(AnnotationRetention.BINARY) annotation class IntelProgrammer @Qualifer @Retention(AnnotationRetention.BINARY) annotation class RyzenProgrammer @Module @InstallIn(SingleTonComponent::class) object ProgrammerModule { @IntelProgrammer @Provides fun providesIntelProgrammer( intelComputer: IntelComputer, ) : Programmer { return Programmer( intelComputer, ) } @RyzenProgrammer @Provides fun providesRyzenProgrammer( ryzenComputer: RyzenComputer, ) : Programmer { return Programmer( ryzenComputer, ) } } @AndroidEntryPoint class IntelProgrammerActivity: AppCompatActivity() { @IntelProgrammer @Inject lateinit var programmer: Programmer } @AndroidEntryPoint class RyzenProgrammerActivity: AppCompatActivity() { @RyzenProgrammer @Inject lateinit var programmer: Programmer }
Android Component를 위한 구성요소
Hilt 구성 요소 | 대상 | 생성 위치 | 소멸 위치 |
---|---|---|---|
SingletonComponent | Application | Application.onCreate() | Application 소멸됨 |
ActivityRetainedComponent | N/A(해당 사항 없음) | Activity.onCreate() | Activity.onDestroy() |
ViewModelComponent | ViewModel | ViewModel 생성됨 | ViewModel 소멸됨 |
ActivityComponent | Activity | Activity.onCreate() | Activity.onDestroy() |
FragmentComponent | Fragment | Fragment.onAttach() | Fragment.onDestroy() |
ViewComponent | View | view.super() | View 소멸됨 |
ViewWithFragmentComponent | @WithFragmentBindings 가 지정된 View | view.super() | View 소멸됨 |
ServiceComponent | Service | Service.onCreate() | Service.onDestroy() |
구성요소 계층 구조
Hilt가 지원하지 않는 클래스에 의존성 주입
- 위와 같이 Android Component는 Hilt가 제공하지만 새로운 Component를 제공하고자 한다면
@EntryPoint
어노테이션을 통해 사용자 정의가 가능하다. EntryPointAccessors
의 적절한 정적 메서드를 사용하여 진입점에 액세스 할 수 있다.- [ 자세한 내용 ]
참고 자료
[Hilt를 사용한 종속 항목 삽입 | Android 개발자 | Android Developers](https://developer.android.com/training/dependency-injection/hilt-android?hl=ko) |