개발/안드로이드

[Hilt] Hilt의 API 활용 및 예제 (2)

스몰스테핑 2024. 8. 7. 15:50

Custom 컴포넌트 만들기

커스텀 컴포넌트란, 사용자가 정의한 컴포넌트로 표준 컴포넌트 하위에 위치시킬 수 있다

 

1. Custom 컴포넌트 정의하기

@DefineComponent(parent = SingletonComponent::class)
interface MyCustomComponent

 

인터페이스를 선언하고 @DefineCompoent 애노테이션을 사용한다.

 

2. Custom 컴포넌트 빌더 정의하기

@DefineComponent.Builder
interface MyCustomComponentBuilder {
    fun setFoo(foo: Foo): MyCustomComponentBuilder

    fun build(): MyCustomComponent
}

 

컴포넌트를 만들기 위한 컴포넌트 빌더를 만든다.

Dagger와 달리 컴포넌트와 컴포넌트 빌더 인터페이스를 나누어 만드는 것이 좋다.

컴파일 타임에 @DefineComponent 애노테이션이 존재하고, 해당 애노테이션을 @InstallIn 애노테이션을 통해 여러 곳에서 참조가 된다면 그때 Builder 코드도 참조되며 불필요한 코드 생성이 이루어질 수 있다.

 

3. Custom 컴포넌트 빌더 제약 조건

  • setter 메서드는 파라미터를 반드시 1개만 가져야하며, 반환 타입은 컴포넌트 빌더 자기 자신을 반환할 수 있다.
  • build 메서드는 파라미터를 가질 수 없으며, 반환 타입은 컴포넌트이다.

++ Custom 컴포넌트를 만들면서 외부에서 생성된 인스턴스를 직접 컴포넌트에 바인딩하고 싶다면 @BindsInstance를 setter 메서드의 파라미터에서 사용하면 된다.

 

4. 커스텀 컴포넌트를 위한 EntryPoint 만들기

@EntryPoint
@InstallIn(MyCustomComponent::class)
interface MyCustomEntryPoint {
    Bar getBar()
}

 

5. 커스텀 컴포넌트 매니저

class CustomComponentManager @Inject constructor (
    componentBuilder: MyCustomComponentBuilder
): GeneratedCompoenentManager<MyCustomComponent> {
    lateinit var component: MyCustomComponent

    fun doSomething(foo: Foo) {
        component = componentBuilder.setFoo(foo).build()
        val bar = EntryPoints.get(component, MyCustomEntryPoint::class.java).getBar()
    }

    override fun generatedComponent(): MyCustomComponent = component
}

 

컴포넌트 빌더를 주입 받아 컴포넌트를 관리하는 주체인 매니저를 만든다.

EntryPoints에서 해당 컴포넌트에 접근할 수 있도록 하여, 주입받은 컴포넌트 빌더를 통해 컴포넌트를 생성한다.

예제 코드에서는 doSomething을 호출하여 컴포넌트 생성과 컴포넌트 바인딩, Bar의존성 까지 가져오게 만들고 있다.

 

6. 커스텀 스코프

@Scope
annotation class MyCustomScoped

@DefineComponent(parent = SingletonComponent::class)
@MyCustomScoped
interface MyCustomComponent

 

커스텀 컴포넌트에 별도의 스코프를 지정하지 않았다면 부모의 스코프를 그대로 따라가게 된다.

하지만, 컴포먼트만의 의존성 제공 범위를 따로 제한하고 싶다면 커스텀 스코프를 선언할 수 있다.

 

@Module
@InstallIn(MyCustomComponent::class)
object MyModule {
    @Provides
    @MyCustomScoped
    fun provideFoo(): Foo {
        
    }
}

 

이후, 의존성이 바인딩되는 부분에서 해당 스코프 애노테이션을 사용하면 된다.

 

7. 커스텀 컴포넌트 단점

  1. 커스텀 컴포넌트/스코프 사용은 오버헤드가 추가된다.
  2. 오브젝트 그래프가 복잡해진다.
  3. 컴포넌트는 하나의 부모 컴포넌트만 갖는다.
  4. 커스텀 컴포넌트는 표준화를 위반한다.

 

 8. 요약

  • 커스텀 컴포넌트를 활용하여 의존성들을 별도로 격리할 수 있다.
  • 커스텀 컴포넌트는 그래프를 복잡하게 하고 성능을 떨어뜨릴 수 있다.
  • 커스텀 컴포넌트보다 표준 컴포넌트의 사용을 추천한다.