https://dagger.dev/hilt/modules


5.4 Core APIs – Modules

Hilt의 모듈은 표준 Dagger 모듈로 @InstallIn이라는 추가적인 어노테이션을 갖는다. @InstallIn은 Hilt의 표준 컴포넌트들 중 어떤 컴포넌트에 모듈을 설치할지 결정한다.

Hilt 컴포넌트가 생성될 때 모듈들은 추가된 @InstallIn과 함께 알맞은 컴포넌트 또는 서브컴포넌트에 설치 된다. Dagger와 같이 컴포넌트에 모듈을 설치하면 해당 모듈에 바인딩된 의존성들은 컴포넌트 내 다른 바인딩 또는 다른 하위 컴포넌트의 바인딩이 접근하는 것을 허용한다. 바인딩 된 의존성에 @AndroidEntryPoint 클래스가 접근 하는 것 또한 가능하다. 해당 컴포넌트의 대한 바인딩 스코프를 지정할 수도 있다.

@InstallIn 사용하기

모듈에서 @InstallIn 어노테이션을 추가하는 것으로 Hilt 컴포넌트에 모듈이 설치 된다. Hilt를 사용할 때 Dagger모듈 상에 이러한 @InstallIn 어노테이션은 필수지만 이 검사는 선택적으로 비활성화 할 수 있다.

Note : 만약 모듈이 @InstallIn 어노테이션을 가지고 있지 않다면 해당 모듈은 컴포넌트에 설치되지 않아 컴파일 에러를 발생 시킨다.

@InstallIn 어노테이션에 어떤 컴포넌트가 모듈이 설치될 적당한 Hilt 컴포넌트인지 명시해야 한다. 예를들면 애플리케이션에서 범위에서 어떤 바인딩이든 사용할 수 있도록 모듈을 설치하려면 ApplicationComponent를 사용해야 한다.

@Module
@InstallIn(ApplicationComponent.class) // 생성되는 ApplicationComponent에 FooModule을 설치함
public final class FooModule {
    @Provides
    static Bar provideBar() {...}
}

각 컴포넌트에는 스코프 어노테이션이 존재하고, 이것은 컴포넌트의 생애동안 바인딩된 인스턴스가 유지될 수 있도록 한다. 예를 들면, ApplicationComponent에 설치되는 모듈의 바인딩에서는 @Singleton 어노테이션을 사용할 수 있다.

@Module
@InstallIn(ApplicationComponent::class)
object class FooModule {
    // @Singleton 프로바이드 메서드는 ApplicationComponent 인스턴스당 한번만 호출된다.
    @Provides
    @Singleton
    fun provideBar(): Bar {...}
}

추가적으로 각 컴포넌트는 컴포넌트 별로 기본적으로 가지고 있는 바인딩들이 있는데 5.1 Components 섹션에서 ‘컴포넌트가 제공하는 기본 바인딩’을 참조하자. 예를 들어, ApplicationComponent에서는 Application 바인딩이 기본적으로 제공된다.

@Module
@InstallIn(ApplicationComponent::class)
object class FooModule {
    // @InstallIn(ApplicationComponent.class) 모듈의 프로바이더 메서드들은 
    // 바인딩 된 Application 객체를 참조하는 것이 가능하다.
    fun provideBar(app: Application): Bar {...}
}

여러 컴포넌트에 하나의 모듈 설치하기

여러 컴포넌트에 하나의 모듈을 설치하는 것이 가능하다. 예를 들면, ViewComponent와 ViewWithFragmentComponent에 있는 바인딩을 가지고 있다고 가정할 때 모듈을 복사해서 사용하는 것을 원치 않을 것이다. @InstallIn({ViewComponent.class, ViewWithFragmentComponent.class}) 으로 작성하면 두 컴포넌트 모듈을 설치할 수 있게 된다.

여러 컴포넌트에 하나의 모듈을 설치할 때 지켜야 할 세가지 규칙이 있다.

  • 모든 컴포넌트가 동일한 스코프 어노테이션을 지원하는 경우에만 프로바이더 메서드의 스코프 어노테이션을 지정할 수 있다. 예를들면, ViewComponent와 ViewWithFragmentComponent 제공된 바인딩은 @ViewScoped를 사용할 수 있다. Fragment와 Service에서 제공된 바인딩은 어떤 스코프 어노테이션을 지정하더라도 같이 사용할 수 없다.
  • 모든 컴포넌트가 이러한 바인딩에 대해 접근이 가능하려면 프로바이더는 스코프 어노테이션 없이 바인딩 주입만 가능해야한다. 예를 들면, ViewComponent와 ViewWithFragmentComponent에 있는 바인딩은 View에 주입할 수 있는 반면에 FragmentComponent와 ServiceComponent의 바인딩은 Service 또는 Fragment에 주입 될 수 없다.
  • 상위 컴포넌트와 하위 컴포넌트는 같은 모듈을 설치 할 수 없다. (대신, 상위 컴포넌트에 모듈을 설치하고 하위 컴포넌트에 해당 모듈의 바인딩에 접근할 수 있다.)

앱 빌드 변형

대부분의 안드로이드 앱은 앱의 빌드 변형에 따라 다른 모듈과 바인딩을 가져오게 된다. (예: 프로덕션, 디버그, 테스트, 기타)

Hilt에서 바이너리의 빌드 대상이 전이적으로 모듈에 의존하는 경우 해당 모듈은 앱의 적절한 컴포넌트에 설치된다. 이를 통해 다른 빌드 대상을 정의하고 바이너리 정의에 다른 의존성을 가져 오는 것처럼 쉽게 구성 할 수 있다.

Bazel: 빌드 파일들 정리하기

Bazel은 더 세밀하게 빌드 대상별로 분리하는 경향이 있기 때문에 @UninstallModules을 사용하여 테스트에서 교체하려는 모듈을 명시하는 대신 모듈을 설치하지 않는 것이 낫다. 왜냐하면 테스트에서 빌드 의존성을 줄이기 때문에 전체적으로 빌드 시간이 빨라질 수 있다.

모듈의 빌드 대상을 구성 할 때 테스트 또는 앱의 다른 구성에서 이 모듈을 교체할 수 있는지 고려해야 한다. 만약 해당 모듈이 교체 될 일이 없다면 자유롭게 다른 소스 코드와 함께 모듈을 포함해도 좋다.

모듈이 교체 가능해야 하는 경우 모듈에 분리된 대상을 생성해야 한다. 그런 다음 각 테스트 루트 (또는 다른 구성 루트)가 모듈 사용 여부를 결정할 수 있도록 앱의 루트에서 이 대상을 가져올 수 있다.

상황에 따른 모듈을들을 고려하여 빌드 대상을 구성하는 두가지 방법이 존재한다.

  • 일반적인 빌드 대상과 함께 간단히 모듈들을 포함한다. 이는 사용자들이 사용하는 라이브러리에 당신이 정의한 내용을 항상 얻게 되는 것을 의미한다.
  • 테스트에서 교체 가능한 바인딩들이 되려면, 안드로이드 바이너리 단계에서 모듈을 나누어야 한다.

기본적으로 첫번째 방식을 선택하는 것을 추천한다. 두번째 방법은 테스트에서 바인딩의 교체가 필요한 경우에만 사용하자. 그렇지만 많은 라이브러리들이 두가지 방식을 모두 사용한다.

카테고리: Dagger2

0개의 댓글

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.