본문 바로가기
안드로이드

[안드로이드] 힐트(Hilt)를 사용하면서 - @Binds

by keel_im 2021. 12. 19.
반응형

오늘은 힐트를 사용하면서 @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

 

Hilt를 사용한 종속 항목 삽입  |  Android 개발자  |  Android Developers

Hilt를 사용한 종속 항목 삽입 Hilt는 프로젝트에서 수동 종속 항목 삽입을 실행하는 상용구를 줄이는 Android용 종속 항목 삽입 라이브러리입니다. 수동 종속 항목 삽입을 실행하려면 모든 클래스

developer.android.com

 


즉, @Provide 는 조금 더 넓은 범위에서 @Binds 는 인터페이스로 주입하고 Impl 로 구현이 되었을 때로 확인할 수 있습니다.

기존에 문제로 돌아가서 두개 코드가 작동할 수 있었던 이유는 @Binds 케이스에서는 Impl 클래스에 제대로 주입이 되었기 때문에 @Binds가 정상 동작한거였다면, @Provides 케이스는 @Inject constructor 안에 필요한 인자들을 전부 주입을 했기 때문입니다. 

그러면 여기서 의문은, Interface 와 InterfaceImpl 에서 주입을 할때 @Inject construct 안에서 주입되는 형태가 아니라 직접 인스턴스를 만들고 동적으로 생성자안에 넣어주어야 하는 상황이면 어떨까요?

@Inject contructor 안에 주입이 되지 않는 경우

고민이 필요한건 이런 부분인 것 같습니다. 저 상황에서는 @Binds 는 사용할 수 없습니다. 왜? 빌드 타임에서 저 location 이 어떻게 주입이 되는 지 알수가 없기 때문입니다. 이런 경우 @Binds 가 아닌 @Provides 를 사용해야만 주입이 완성될 수 있습니다. 

정리하자면, @Inject constructor 에서 바로 주입이 가능하고 Interface 와 InterfaceImpl 관계가 성립된다면 @Binds 를 그 외 경우는 @Provides 를 사용하기로 하였습니다. 


저는 위 사실을 깨닫고 가지고 있던 코드를 수정하기 시작했습니다. 정말 간편하게 줄더라구요. 정말 배울것이 많은 것임을 새삼 또 느낍니다. 

힐트를 쓰면서 왜 멀티 모듈이나 클린 아키텍처를 쓰는지 체감을 하는 것 같습니다. 특히 koin 또한 편리한 DI 라이브러리이긴 하지만, Dagger(Hilt) 와 차이점이라고 한다면, 단연 컴파일 타임과 런타임의 차이? 라고 설명할 수 있을 것 같습니다. 이 얘기는 거꾸로 말하면 Dagger(Hilt) 를 사용한다면 그 만큼 빌드 시간이 늘어나는 것입니다. 

kapt 에서 빨리 ksp 가 도입되는 날을 기다리고 싶습니다. 

https://github.com/google/ksp

 

GitHub - google/ksp: Kotlin Symbol Processing API

Kotlin Symbol Processing API. Contribute to google/ksp development by creating an account on GitHub.

github.com

오늘은 힐트에 대해 여기까지 다루겠습니다. 다음에도 개발하면서 겪은 경험들은 써보겠습니다.

🧶문서는 항상 수정될 수 있습니다. 비판은 환영합니다.

 

반응형

댓글