View
오늘의 알아볼것!
오늘은 의존성 주입을 도와주는 hilt에 대해서 알아보려고 한다. 그러기 위해서는 간단히 의존성 주입부터 천천히 알아 보자!
DI (?ㅅ?)
다들 "DI"라는 말은 안드로이드 개발자라면 귀가 뚫어 지게 들어봤을 것이다. 사실 개발자라면 본인도 모르는세 쓰고 있을 것이다.
그럼 이 "DI"뭔지 간단히 알아보자
DI
는 Dependency Injection
의 약자로 말 그대로 의존성 주입
을 말한다.
의존성이란 말은 함수에 필요한 클래스, 참조변수, 객체에 의존한다는 것을 말한다.
간단히 말하자면 A클래스를 만들기 위해서 B클래스가 필요한 경우
B클래스는 A클래스의 의존 대상이 되는 것이다.
즉 자동차를 만들때 타이어가 필요한 것을 볼 수 있다. 이런 경우 자동차를 만드는 회사는 타이어를 직접 생산하지 않으므로, 타이어 회사에 의존하게 된다. 이런 경우 타이어 회사는 자동차 회사의 의존 대상이 되는 것이다.
의존성 주입의 유무에 따라 간단한 예시를 들어서 보자
아래 코드는 의존성 주입이 없는 코드이다.
class Car {
private val tire = Tire()
fun go() {
tire.go()
}
}
fun main(args: Array) {
val car = Car()
car.go()
}
// 해당 예제에서는 Tire와 Car의 결합이 강해 Car는 Tire의 서브 클래스를 사용하기가 어려워진다.
// Tire의 생성자가 변경된 경우 Car 클래스도 수정해야된다.
// Tire의 실제 인스턴스를 사용하기 때문에 다양한 시나리오를 고려하지 못해 테스트가 어렵다.
아래 코드는 의존성 주입을 한 코드이다.
class Car(private val tire: Tire) {
fun go() {
tire.go()
}
}
fun main(args: Array) {
val tire = Tire()
val car = Car(tire)
car.go()
}
// Tire와 Car의 결합이 낮아지며, Car를 재사용하기 쉬워지고, 테스트하기도 쉬워진다.
위 코드는 Car의 각 인스턴스를 초기화 할때 Tire 객체를 생섲아 파라미터로 받게 된다.main()
에서 Tire
인스턴스를 생성하고, 이를 활용해 Car
인스턴스를 만들게 되어 여러 이점을 챙긴다.
Car
의 재사용성이 높다. 예를 들어서HanaTire
와 같은Tire
의 서브클래스를 넘겨주는 등,Tire
의 다양한 구현을Car
에 전달할 수 있다.Tire
의 생성자 등 구현이 변경되어도,Car
클래스를 수정하지 않아도 된다.Car
에 대한 유닛 테스트가 편리해진다. 즉, 다양한 시나리오를 테스트해볼 수 있다.
DI의 장점
- Unit Test가 용이하다.
- 코드의 재사용성이 높아진다.
- 리팩토링이 수월해진다.
- 객체 간의 의존성을 줄이거나 없앨 수 있다.
- 객체 간의 결합도를 낮추며 유연한 코드를 짤 수 있다.
DI의 단점
- 의존성 주입을 위한 선행 작업이 필요하다.
- 코드를 추적하고 읽기가 어려워진다.
하지만 장점이 더 많다.ㅎㅅㅎ
Hilt
그렇다면 오늘 알아볼 Hilt는 무엇일까
Hilt는 Google의 Dagger2를 기반으로 만든 DI 라이브러리다.
Dagger보다 표준화된 컴포넌트 세트, 스코프 설정으로 가독성/이해도 증가, 다양한 빌드 타입에 대해 다른 바인딩을 제공한다.
hilt의 특징
- Dagger2보다 표준화된 사용벙을 제시하고 보일러 플레이트 코드를 감소
- 실제로 구글 샘플 앱을 Dagger에서 Hilt로 바꾸니 결과, 코드가 반으로 줄었다고 한다.
- 쉬운 모듈 탐색과 통합, 개선된 테스트 환경, 프로젝트 설정 간소화 등 다양한 장점이 존다.
즉 Hilt는 Dagger2라는 DI 라이브러를 기반으로 만들었으며, 사용이 쉽다는 것이다.
우리는 Hilt를 사용하기 위해서 Hilt에서 제공해주는 어노테이션과 컴포넌트를 사용해서 모듈을 만들어 의존성을 주입 시길 수 있다.
간단한 hilt 적용
hilt를 사용하기위해서는 Application에서 @HiltAndroidApp를 설정해 줘야되고, 의존성 주입은 onCreate의 super.onCreate()에서 바이트 코드로 변환 뒤 이루어진다.
(내부 코드를 보면 Hilt_MemoApplication으로 생성되었을 것이다.)
@HiltAndroidApp
class MemoApp : Application()
Hilt의 의존성 주입은 바로 @Inject을 통해서 주입이 가능하다.
아래 코드처럼 말이다.
class MemoRepository @Inject constructor (private val db : SQLiteDatabase){
fun load(id : String) {...}
}
Activity에서 @AndroidEntryPoint라는 어노테이션을 붙여 사용가능
이 외에 Activity, Fragment, View, Service, BroadcastReceiver도 사용 가능합니다.
또한 생성자 외에도 변수에 @Inject를 할 수 있습니다.
단, lateinit으로 설정해야 합니다(private도 금지다.!!)
아래는 예제 코드이다.
@AndroidEntryPoint
class MemoActivity : AppcompatActivity{
@Inject lateinit var repository : MemoRepository
override fun onCreate(savedInstanceState : Bundle){
super.onCreate(bundle)
repository.load("...")
}
}
@EntryPoint
@InstallIn(SingletonComponent::class)
interface FooBarInterface{
fun getBar() : Bar
}
// EntryPoint 활용
val bar = EntryPionts.get(applicationContext, FooBarInterface::class.java).getBar()
그리고 의존성 주입을 위한 모듈을 만드는 코드는 아래와 같다.
@InstallIn(SingletonComponent::class)
@Module
object DataModule{
@Provides
fun provideMemoDB(@ApplicationContext context : Context) =
Room.databaseBuilder(context, MemoDatabase::class.java, "Memo.db").build()
}
@InstallIn: Hilt가 생서하는 DI 컨테이너에 어떤 모듈을 사용할지 가르킨다.
@Module: InstallIn으로 설정한 객체들의 모음입니다.
@Provides: 의존성 주입을 합니다.
@ApplicationContext: applicationContext를 제공합니다.
간단히 그림을 통해서 살펴보자면
출처: 드로이드나이츠 2020. 옥수환 - hilt
- @HiltAndroidApp을 통해 ApplicationComponent가 생성됩니다.
- @InstallIn을 통해 해당 컴포넌트의 모듈이 생성됩니다.
- MemoActivity에 @AndroidEntryPoint를 통해 ActivityComponent가 생성됩니다.
- 이제 MemoRepository를 주입받을 수 있습니다.
hilt 컴포넌트 계층
Hilt에서는 Adroid환경에서 표준적으로 사용되는 컴포넌트들을 기본적으로 제공해준다.
내부적으로 제공하는 해당 컴포넌트들의 전반적인 라이프 사이클 또한 자동으로 관리해준다.
아래 사진은 Hilt에서 제공하는 표준 컴포넌트 계층이다.
이렇게 봐도 솔직히 처음 사용하면 헷갈릴 것이다.!!
결국 프로젝트에 적용해보는게 시간은 오래 걸리지만 확실하다.(물론 오래건린다. 그래도 감은 잡을 수 있다.)
내가 생각하는 힐트의 사용법에서 기억할 것은(글쓴이의 생각 어려우면 그냥 잊으세용 ㅋㅅㅋ)
- @HiltAndroidApp를 설정해서 hilt를 해당 프로젝트에서 사용하겠다는 것을 알려주고
- @InstallIn, @Module, @Provides를 사용해서 어디에다가 어떤 것을 의존시킬 거인지 알려주는
안내서(설계도)
같은 모듈을 짠다 - @Inject라는 라벨을 통해서 실제 안내서 말한대로 의존성을 주입시켰다고 알려준다.
- 또한 해당 안내서의 내용을 사용한 곳이 Activity일 경우 @AndroidEntryPoin라는 라벨을 붙여준다고 생각했다.
- 즉 실제 힐트를 사용하고 적용하는 어노테이션은 @HiltAndroidApp와 모듈이며 나머지 어노테이션은 그냥 일종의 해당 부분에 Hilt를 사용할 거라는 라벨이라고 본다.
참조블로그 -> [문바리](https://moonbari.tistory.com/99)
'TIL > 스터디' 카테고리의 다른 글
코루틴-1(Coroutine) (0) | 2024.03.06 |
---|---|
Calendar 클래스 (0) | 2024.02.29 |
안드로이드 Task(간단 포스트) (0) | 2024.02.26 |
Subject 클래스(PublishSubject, ReplaySubject) (0) | 2024.02.22 |
Subject 클래스(AsyncSubject, BehaviorSubject) (0) | 2024.02.21 |