→ Android에서 DI를 위한 라이브러리이다. Android의 Activity, Fragment 등 주요 component 들에서 사용할 의존성 객체를 관리해준다. Android 용으로 만들어서 선배 DI 라이브러리인 Dagger보다 훨씬 쓰기 쉽다.
→ 의존성 주입(Dependency Injection)! 특정 a 클래스의 객체가 필요할 때 사용처에서 직접 생성하는 것 보다 전달 받는것이 테스트에도 용이하고 보일러 플레이트 코드를 줄일 수 있고 객체 생성에 필요한 조건이 변경됐을 때 편하게 대응이 가능하다.
Hilt가 Dagger를 기반으로 만들어졌고, 더 편하고, 요즘(2022.07.28 기준) Android 씬에서 DI가 아주 핫한 디자인 패턴이며 hilt가 Android DI에 필수적인 라이브러리이다.
대충 이정도만 짚고 넘어가자.
시작!
일단 dependency 추가 먼저 해주자
// gradle(project)
buildscript {
dependencies {
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.42'
}
}
// gradle(app)
plugins {
id 'dagger.hilt.android.plugin'
id 'kotlin-kapt'
}
dependencies {
implementation "com.google.dagger:hilt-android:2.42"
kapt "com.google.dagger:hilt-android-compiler:2.42"
}
@HiltAndroidApp
class MyApplication : MultiDexApplication() {...}
@HiltAndroidApp
어노테이션이 모든 작업의 시작점이다. Hilt를 사용하는 모든 앱은 이 어노테이션을 추가한 Application class를 정의해야 한다. @HiltAndroidApp
이 Application의 생명주기를 참고하여 컴파일 타임 때 필요한 클래스들을 초기화 해주고 의존성 객체를 제공한다.
시작이 반이니 벌써 절반 했다.
이제 의존성을 주입 받아 보쟈. Hilt는 Application
, Activity
, Fragment
, Service
, View
, BroadcastReceiver
, ViewModel
컴포넌트들에 의존성 주입을 도와준다.
Application Class와 마찬가지로 클래스 상단에 어노테이션을 추가해주자.
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {...}
프래그먼트에 지정하면 프래그먼트가 띄워진 액티비티에도 달아주어야 한다.
의존성 주입 방식에 2가지 경우가 있다.
참고: https://f2janyway.github.io/android/hilt/
-> 내가 구현한 클래스
-> 인터페이스 or abstract class 구현체(@Module
사용)
-> 내가 구현할 수 없는 클래스(3rd party library)(@Module
사용)
class DateFormatter @Inject constructor() {
...
}
class의 constructor에 @Inject
붙여준다, 초간단
인스턴스 주입을 위한 모듈을 만들어보자!
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Singleton
@Provides
fun provideOkHttpClient(): OkHttpClient {...}
어쩌고 저쩌고 구글링 해보면 죄다 Dagger의 개념과 함께 설명하느라 말을 너무 어렵게 한다.(내 기준 ㅎ)
Dagger를 알면 좋겠지만 나중에 하는것으로 하고… 쉽게쉽게 알아보자
@Module
은 컴포넌트에 의존성을 제공하는 역할을 한다. 모듈 클래스 내에 선언되는 메서드에 @Provides
를 붙여 컴파일 타임에 의존성을 제공하는 프로바이더를 생성한다. (긍까 간단히 Hilt에게 해당 의존성을 주입하는 방법을 알려준다.)
더 간단히!! @Module
은 의존성을 제공하는 클래스에 붙이고, @Provides
는 의존성을 제공하는 메소드에 붙인다!
@Provides
는 외부 라이브러리 처럼 클래스를 직접 소유하지 않아서 인스턴스 생성 방법을 모르는 경우 지정해준다.
@Binds
→ Abstract인 경우 사용
@Installin
은 간단히 해당 모듈을 Hilt 표준 컴포넌트들 중 어떤 컴포넌트에 설치할 것인지 결정한다.
간단히!! 해당 모듈에 접근할 수 있는 범위를 지정한다! 컴포넌트들은 밑에 정리.
Dagger에서는 컴포넌트를 직접 정의했어야 하나 보다. Hilt는 제공해주는 위의 컴포넌트들을 편하게 쓰면 된다~
모듈의 Installin에서 지정한 컴포넌트의 스코프와 모듈 내에서 제공되는 인스턴스들의 scope는 동일해야한다. (ex @Installin(ActivitiyComponent.class
) 로 설정했으면 해당 모듈의 메소드들의 scope도 다 @ActivityScoped
로 지정해줘야 함.)
따로 scope를 지정하지 않으면 주입이 일어날 때 마다 인스턴스를 생성하고, GC에 의해 삭제됨.
scope를 달아주면 해당 scope에 맞게 create, destroy됨.
이제 의존성 주입을 받자!
@AndroidEntryPoint
class ChangePasswordFragment : Fragment() {
private lateinit var binding: FragmentChangePasswordBinding
@Inject
lateinit var userRepository: UserRepository
@AndroidEntryPoint
를 붙인 곳에서 @Inject
를 통해 의존성 주입 받는다, 초간단
Dagger에서는 기존에 ViewModelProvider를 이용해 직접 뷰모델 inject를 위해 multi 어쩌고 저쩌고를 활용해 직접 구현해줬어야 했는데 이 과정을 @HiltViewModel
이 자동으로 자~알 어디다가 만들어주고 뷰모델 사용처에서 viewModels
확장 함수를 통해 간단히 뷰모델의 의존성을 주입 받을 수 있다.
더 자세한 디테일들은 알아서 찾아보시길……….
Hilt에 대해 더 자세히 이해하기 위해서는 Dagger를 이해하는것이 필요하겠지만 (공부하기 시렁)
일단은 이정도만 이해해도 Hilt를 사용하는데에는 지장 없을 듯 싶다.
Component와 Scope를 정할 때 신경을 쓰는것이 중요하다고 생각된다.
끝!
간단하게 잘 정리하셨네요! 나중에는 적용기도 보여주세요!!