Hilt의 표준 컴포넌트

MSU·2024년 8월 3일

Android

목록 보기
12/36
post-thumbnail

표준 컴포넌트

Hilt는 표준컴포넌트를 제공해주기 때문에 개발자가 직접 컴포넌트를 만들 필요가 없다.(만들 수는 있음)


각 화살표의 방향은 하위 컴포넌트를 가리킨다.

하위 컴포넌트에서 상위 컴포넌트의 의존성에 접근하는 것은 가능하다.
하지만 상위 컴포넌트에서 하위 컴포넌트의 의존성에 접근하는 것은 불가능하다.

안드로이드 컴포넌트에 대응 되는 Hilt 컴포넌트

ComponentInjector for
SingletonComponentApplication
ViewModelComponentViewModel
ActivityComponentActivity
FragmentComponentFragment
ViewComponentView
ViewWithFragmentCompnentView with @WithFragmentBindings
ServiceComponentService

Scope가 없으면 매 요청시 새로운 인스턴스를 생성하게 된다.

class UnscopedBinding @Inject constructor() {
}

Scope annotation이 있으면 해당 Hilt 컴포넌트의 수명동안은 매 요청에 동일한 인스턴스 반환을 보장한다.

@FragmentScoped
class ScopedBinding @Inject constructor() {
}

하지만 모든 프래그먼트가 동일한 인스턴스를 공유하지는 않는다.
왜냐하면 프래그먼트별로 개별 바인딩 인스턴스를 사용하기 때문

모듈에서 Scope 지정하기

@Module
@InstallIn(FragmentComponent::class)
object FooModule{
	// 스코프 없음
    @Provides
    fun provideUnscopedBinding() = UnscopedBinding()
    
    // 스코프 있음
    @Provides
    @FragmentScoped
    fun provideScopedBinding() = ScopedBinding()
}

Scope annotation은
1. 어떤 의존성을 인스턴스화하는 비용이 클 때
2. 동일한 인스턴스 반환을 원할 때
3. 특정 인스턴스를 공유하고 싶을 때
써야 한다.

Hilt에서 기본으로 제공되는 바인딩

ComponentDefualt Bindings
SingletonComponentApplication
ActivityRetainedComponentApplication
ViewModelComponentSavedStateHandle,
ViewModelLifecycle
ActivityComponentApplication, Activity
FragmentComponentApplication, Activity, Fragment
ViewComponentApplication, Activity, View
ViewWithFragmentCompnentApplication, Activity, Fragment, View
ServiceComponentApplication, Service

Hilt의 Component도 Component와 SubComponent로 이루어져있으며,
엄밀히 보자면 Hilt에서는 SingletonComponent 외에는 전부 SubComponent이다.

@AndroidEntryPoint

안드로이드 클래스에서도 @AndroidEntryPoint로 의존성 주입을 활성화 시킬 수 있다.
@AndroidEntryPoint가 지원하는 타입
1. Activity
2. Fragment
3. View
4. Service
5. BroadcastReceiver (SingletonComponent 사용만)
BroadcastReceiver는 자신만의 컴포넌트를 갖고 있지 않기 때문에 SingletonComponent를 통해서만 의존성을 주입받을 수 있다.

안드로이드 클래스에서 의존성 주입시, 상위 (서브)컴포넌트에도 반드시 @AndroidEntryPoint를 선언해줘야 한다.

@AndroidEntryPoint
class MyActivity: ComponentActivity(){
	// MyActivity 실행
}

@AndroidEntryPoint
class MyFragment: Fragment(){
	// 의존성 주입
}

프래그먼트에서 의존성 주입을 받는 경우에는 액티비티에도 @AndroidEntryPoint를 붙여줘야 한다.

@AndroidEntryPoint 주의사항

  1. Hilt는 ComponentActivity를 상속한 Activity만 지원한다.
    보통 Acitivity가 AppCompatAcitivity를 상속받고 있는데, AppCompatAcitivity도 ComponentAcitivity의 SubComponent이므로 가능하다.
  2. Hilt는 androidx 라이브러리에 포함된 Fragment만 지원한다.
  3. Android SDK에 포함된 Fragment는 Deprecated 되었으며 지원하지 않는다.

Retained Fragments

프래그먼트 instance를 유지할지 말지 결정하는 메서드가 retainInstance인데 이 값을 true로 셋팅하면 화면 전환에도 instance를 유지할 수 있게 된다.
하지만 Hilt를 같이 사용하는 경우에는 컴포넌트에 바인딩 된 instance가 scope annotation을 달았더라도 유지되지 않기 때문에 retainInstance 사용을 권장하지 않는다.
애초에 Hilt가 아니어도 프래그먼트에서 instance를 유지하려는 것 자체가 지금 와서는 안티 패턴이라고 한다.
대신 상위 컴포넌트에 바인딩하거나 뷰모델을 사용하는 방법으로 retainInstance을 대체하면 메모리 관리나 유지보수 측면에도 좋은 방법이 된다고 한다.

Fragment 바인딩을 View와 함께 운용하기

@AndroidEntryPoint
@WithFragmentBindings
class MyView: View() {
	@Inject lateinit var bar: Bar
}

컴포즈를 사용하는 프로젝트에서는 @WithFragmentBindings를 사용할일이 없다.
View를 확장하고 커스텀 뷰를 만드는 경우에도 사용된다.

모듈

프로그램을 구성하는 요소, 관련된 데이터와 함수를 하나로 묶은 단위
보통 하나의 소스파일에 모든 기능을 작성하지 않고, 기능별로 모듈을 구성한다.
이러한 모듈을 합쳐서 하나의 실행 가능한 프로그램을 만든다.

Dagger와 Hilt에서는 컴파일 타임에 Component에 Module을 설치하는 방식으로 의존성 주입 셋팅이 이루어진다.

모듈이 설치되는 과정
컴파일 타임, annotation 처리 -> @Module 탐색 -> @InstallIn에서 설치될 컴포넌트 탐색 -> 해당 컴포넌트에 설치

@InstallIn

@Module
@InstallIn(SingletonComponent::class)
object FooModule {
	
    @Singleton // 애플리케이션이 끝날 때까지 Bar는 메모리에 남게 된다.(메모리 누수 유발 효과)
    @Provides
    fun provideBar(app: Application): Bar { 
    	app 
        // SingletonComponent는 기본 바인딩으로 Application 제공한다.
        // 모듈에서 @Provides가 붙은 함수는 Application을 파라미터로 받고 자신이 설치될 Component 바인딩에 접근이 가능하다
    }
}

@InstallIn annotation이 없는 경우에는 컴파일 타임에 에러가 발생하게 된다.
@Module를 선언하면 반드시 @InstallIn도 선언해줘야 한다.

여러 컴포넌트에 모듈 설치

@InstallIn(ViewComponent::class, ViewWithFragmentComponent::class)
  1. 컴포넌트에 접근하여 제공되는 바인딩들은 모두 동일한 스코프에 있어야 한다.
  2. 선언된 컴포넌트들의 바인딩에 접근가능하며, @Provides 함수에 주입할 수 있어야 한다.
  3. 하위 및 상위 컴포넌트 계층 간에는 동일한 모듈을 설치할 수 없다.

Nullable 바인딩은 지양한다.

  1. Hilt는 자바코드에서 null 바인딩을 금지하고 있다.
  2. 자바 코드에서 의존성 바인딩 및 요청 시 @Nullable annotation을 사용해서 우회할 수 있다.
  3. 코틀린에서는 문법 자체적으로 null assign을 금하고 있으나, Nullable 타입이 존재한다.
  4. 실제로 Hilt는 자바 기반이므로 코틀린으로 작성한 Nullable 바인딩이 가능하다.
  5. 그래도 null-safety한 코드를 위해 nullable한 의존성은 지양하자
profile
안드로이드공부

0개의 댓글