Hilt를 사용하여 의존성 주입을 할 때 Module을 정의하여 특정 유형의 인스턴스를 제공하는 방법을 Hilt에게 알려주어야 하는 경우가 있다.
이 때 Module에서 사용하는 @Binds, @Provides 어노테이션에 대하여 설명하고자 한다.
인터페이스 형식은 왜 Hilt가 바로 제공할 수 없을까?
바로 구현체가 무엇인지 알 수 없기 때문이다. @Binds 어노테이션은 인터페이스의 인스턴스를 제공해야 할 때 사용할 구현을 Hilt에 알려준다.
또한 다음과 같은 특징이 존재한다.
@Module
@InstallIn(ActivityComponent::class)
abstract class AnalyticsModule {
@Binds
abstract fun bindAnalyticsService(
analyticsServiceImpl: AnalyticsServiceImpl
): AnalyticsService
}
위처럼 AnlayticsService 인터페이스 형식을 반환한다고 알려주고, 파라미터에 제공할 인터페이스의 구현체를 넣어주면 Hilt가 AnalyticsService 형식을 주입해야 할 경우 해당 구현체를 제공한다.
인터페이스 뿐 아니라 클래스가 외부 라이브러리에서 제공되므로 클래스를 소유하지 않은 경우(Retrofit, OkHttpClient 또는 Room 데이터베이스와 같은 클래스) 또는 빌더 패턴으로 인스턴스를 생성해야 하는 경우에도 생성자 삽입이 불가능하다. 이 경우는 @Provides 어노테이션을 이용하여 Module에 어떤 방식으로 인스턴스를 제공하는지 정의하여 Hilt에 알려준다.
@Provides
fun provideAnalyticsService(): AnalyticsService {
return Retrofit.Builder()
.baseUrl("https://example.com")
.build()
.create(AnalyticsService::class.java)
}
}
코드에서 차이점이 느껴지는가? @Binds는 구현체를 정의하여 알려주기만 하면 되고, @Provides는 인스턴스가 어떤 방식으로 생성되는지 정의하여 알려주어야 한다.
결론은 아니다.
@Binds는 @Provides의 특수한 형태일 뿐이며, @Provides와 같은 역할을 한다. 다른 점은 Binds에는 여러 제약이 있고, 제약이 많은 만큼 코드를 덜 생성한다는 점이다. 빌드 후 app/build 폴더에 가보면 @Binds 와 @Provides 의 클래스 생성양 차이가 다르다. 따라서 상황에 맞게 생성 하는것을 추천한다.
참고 포스트:
https://developer.android.com/training/dependency-injection/hilt-android?hl=ko
https://kotlinworld.com/106