안드로이드 의존성 주입과 Hilt (1)

학습 자료로 드로이드나이츠 인터넷 강의를 참고했습니다.

https://www.youtube.com/@DroidKnights

 

DroidKnights

 

www.youtube.com

 

의존성 주입 ( Dependency Injection)

생성자 또는 메서드 등을 통해 외부로부터 생성된 객체를 전달받는 것 

클래스간 결합도를 느슨하게 하며, 인터페이스 기반으로 설계뙤어 코드를 유연하게 한다.

Stub 또는 Mock 객체를 사용하여 단위테스트를 하기가 더욱 쉬워진다.

 

[ 의존성 주입을 사용하지 않은 경우 ]

의존성 주입이 없는 경우 아래 코드와 같이 데이터 베이스에 접근한다.

내부에서 자체적으로 데이터베이스의 객체 생성을 책임지고 있다.

아래와 같은 방식으로 인스턴스를 생성해서 저장된 메모리를 불러온다.

 

[ 의존성 주입을 사용한 경우 ]

위와 코드는 동일하지만, 데이터베이스 객체 생성에 대한 책임을 내부에서 처리하지 않는다.

외부에서 데이터베이스 객체를 생성하고, 생성자의 매개변수로 데이터베이스를 전달 받는 구조를 사용한다.

 

안드로이드에서 의존성 주입이 어려운 이유

- Android 클래스가 Framework에 의해 인스턴스화 된다.

- 클래스 내부에 개발자가 직접 생성자를 만들거나, 생성자의 매개변수를 전달할 방법이 없다.

- Factory를 API28부터 제공하지만, 현실적이지 않다.

 

해결책 1 : Dagger2 사용

Dagger2는 자바와 안드로이드를 위한 강력하고 빠른 의존성 주입 프레임워크이다.

 

[ 장점 ]

- 컴파일 타임에 그래프를 구성

- 생성된 코드는 명확하고 디버깅이 가능함

- 리플렉션, 런타임 바이트 코드를 사용하거나 생성하지 않음

- 자원 공유의 단순화

- 작은 라이브러리 크기

- 상위 10000개의 안드로이드 앱 중 74%가 Dagger 사용

 

[ 단점 ]

- 배우기 어렵고, 프로젝트 설정이 힘듦

- 간단한 프로그램을 만들 때는 번거로움

- 같은 결과에 대한 다양한 방법이 존재

- 개발자 중 49%의 개발자가 DI 솔루션의 개선을 요청

 

[ 궁극적인 목표 ]

- 정확한 사용방법 제안

- 쉬운 설정 방법

- 어려운 설정 때문에 dagger 대신 koin을 사용하기도 함 

- 중요한 것들에 집중할 수 있도록 해야 함

- 컴파일 에러를 검출 한다는 큰 장점을 가지고 있음  

- 반면에 컴파일 에러가 빈번하게 발생한다면 개발자의 생산성을 저하 시킴

 

Hilt의 사용

Hilt는 애플리케이션에서 DI를 사용하는 표준적인 방법을 제공한다.

 

[ 목표 ]

- Dagger 사용의 단순화

- 표준화된 컴포넌트 세트와 스코프로 설정과 가독성/ 이해도 쉽게 만들기

- 쉬운 방법으로 다양한 빌드 타입에 대한 다른 바인딩 제공 

 

build.gradle 파일에 의존성을 추가한다.

dependencies {
    implementation 'com.google.dagger:hilt-android:2.38.1'
    kapt 'com.google.dagger:hilt-android-compiler:2.38.1'
}

kapt는 바이트 코드 변환을 위한 추가적인 플러그인을 제공한다.

프로젝트 최상위 빌드 그래들 파일에 아래와 같은 플러그인을 추가해야 한다.

 

[ Hilt의 특징 ]

- Dagger2 기반의 라이브러리

- 표준화된 Dagger2 사용법을 제시

- 보일러플레이트 코드 감소 ( 의존성 주입 코드를 75% 이상 감소 )

- 프로젝트 설정 간소화

- 쉬운 모듈 탐색과 통합

- 개선된 테스트 환경 지원

- AndoroidX 라이브러리와 호환

- 뷰 모델과 매니저 컴포넌트와 함께 사용할 수 있음 

 

아래와 같이 @Inject 어노테이션이 생성자에 붙게 된다.

이는 의존성 주입을 받겠다는 것을 의미한다.

이제 인스턴스를 생성하는 부분에서 HiltAndroidApp 의존성을 추가한다.

이 의존성을 통해서 메모리 주입을 위한 기반 작업은 완료된다. (디폴트 어노테이션으로 사용)

이 외에 여러 종류의 어노테이션을 통해서 의존성 주입을 적용한다.

데이터베이스 클래스에서는 Module 클래스를 통해서 주입을 진행한다.

모듈 어노테이션이 달린 모듈 클래스에 InstallIn 어노테이션을 추가한다.

모듈 클래스 내부에 데이터베이스 객체를 생성하는 Provides를 생성하여 작업을 완료한다.

이제 메모 액티비티에서 메모리 데이터베이스를 주입받을 수 있게 된다.

 

 

Object graph

HiltAndroidApp을 통해서 애플리케이션 컴포넌트를 먼저 생성하고,

모듈 클래스에 추가한 인스톨 어노테이션을 통해서 해당 컴포넌트에 모듈이 설치되게 된다.

AndroidEntryPoint를 메모 엑티비티에 추가하는 것으로 애플리케이션 컴포넌트의 하위 컴포넌트인 

액티비티 컴포넌트가 생성되고, MomoRepository 객체를 주입 받을 수 있게 된다.

 

 

내용이 길어져서 여기까지 포스팅하고, 다음 포스팅에서 주요 Hilt Annotation과 실제 코드에 적용하는 방법을 배워보겠다.