오늘은 힐트를 사용하면서 @Binds 에 대해 다시 생각을 해보는 기회를 가졌습니다.
먼저 코드를 보겠습니다.
@InstallIn(SingletonComponent::class)
@Module
internal object StationModule {
@Provides
@Singleton
fun provideStationRepository(
stationArrivalsApi: StationArrivalsApi,
stationApi: StationApi,
appDatabase: AppDatabase,
preferenceManager: SharedPreferenceManager,
@IoDispatcher dispatcher: CoroutineDispatcher,
): StationRepository {
return StationRepositoryImpl(
stationArrivalsApi,
stationApi,
appDatabase.dao(),
preferenceManager,
dispatcher
)
}
}
위 코드는 리팩토링 전에 코드 입니다.
@Binds
abstract fun bindsStationRepository(
repository: StationRepositoryImpl,
): StationRepository
정말 많은 양의 코드가 줄어든 것을 확인할 수 있습니다. 이는 @Binds 라는 어노테이션을 활용하면서 힐트에서 자동으로 처리를 해주는 것인데요. 이를 확인해보고자 합니다.
먼저, 동작은 확인했습니다. 1번 코드와 2번 코드로 빌드를 했을때, 성공적으로 DI 가 되었음을 확인하였습니다.
그러면 왜 이렇게 작동할 수 있을까요?
먼저, @Binds 작동에 대해 공식문서를 확인해보겠습니다.
이 어노테이션은 정의 그대로 인터페이스의 인스턴스를 제공했을 때, 사용하는 것입니다. 그럼 @Provides 를 한번 보겠습니다.
@Provides 는 어떤 유형의 인스턴스 주입한다고 할 수 있습니다.
https://developer.android.com/training/dependency-injection/hilt-android
즉, @Provide 는 조금 더 넓은 범위에서 @Binds 는 인터페이스로 주입하고 Impl 로 구현이 되었을 때로 확인할 수 있습니다.
기존에 문제로 돌아가서 두개 코드가 작동할 수 있었던 이유는 @Binds 케이스에서는 Impl 클래스에 제대로 주입이 되었기 때문에 @Binds가 정상 동작한거였다면, @Provides 케이스는 @Inject constructor 안에 필요한 인자들을 전부 주입을 했기 때문입니다.
그러면 여기서 의문은, Interface 와 InterfaceImpl 에서 주입을 할때 @Inject construct 안에서 주입되는 형태가 아니라 직접 인스턴스를 만들고 동적으로 생성자안에 넣어주어야 하는 상황이면 어떨까요?
고민이 필요한건 이런 부분인 것 같습니다. 저 상황에서는 @Binds 는 사용할 수 없습니다. 왜? 빌드 타임에서 저 location 이 어떻게 주입이 되는 지 알수가 없기 때문입니다. 이런 경우 @Binds 가 아닌 @Provides 를 사용해야만 주입이 완성될 수 있습니다.
정리하자면, @Inject constructor 에서 바로 주입이 가능하고 Interface 와 InterfaceImpl 관계가 성립된다면 @Binds 를 그 외 경우는 @Provides 를 사용하기로 하였습니다.
저는 위 사실을 깨닫고 가지고 있던 코드를 수정하기 시작했습니다. 정말 간편하게 줄더라구요. 정말 배울것이 많은 것임을 새삼 또 느낍니다.
힐트를 쓰면서 왜 멀티 모듈이나 클린 아키텍처를 쓰는지 체감을 하는 것 같습니다. 특히 koin 또한 편리한 DI 라이브러리이긴 하지만, Dagger(Hilt) 와 차이점이라고 한다면, 단연 컴파일 타임과 런타임의 차이? 라고 설명할 수 있을 것 같습니다. 이 얘기는 거꾸로 말하면 Dagger(Hilt) 를 사용한다면 그 만큼 빌드 시간이 늘어나는 것입니다.
kapt 에서 빨리 ksp 가 도입되는 날을 기다리고 싶습니다.
오늘은 힐트에 대해 여기까지 다루겠습니다. 다음에도 개발하면서 겪은 경험들은 써보겠습니다.
🧶문서는 항상 수정될 수 있습니다. 비판은 환영합니다.
'안드로이드' 카테고리의 다른 글
[안드로이드] 앱 오프닝 광고 구현 Version: Kotlin (0) | 2022.01.14 |
---|---|
[안드로이드] repeatOnLifecycle 을 사용하며. (0) | 2021.12.26 |
[안드로이드] SDK 31 대응 사항 중 PendingIntent 에 관하여 (0) | 2021.12.07 |
[안드로이드] Firebase Interceptor - with OkHttp3, Retrofit (0) | 2021.11.25 |
[안드로이드] 컴포즈로 조금씩 바꿔보자. (with Progress bar) (0) | 2021.09.29 |
댓글