Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 안드로이드스튜디오
- cursor
- MVVM
- Android
- RecyclerView
- build
- Kotlin
- ADB
- hilt
- 에러
- 스튜디오
- Gradle
- studio
- DI
- 안드로이드 스튜디오
- 코틀린
- coroutine
- WebView
- 코루틴
- compose
- 안드로이드
- Github
- 의존성주입
- Retrofit
- 웹뷰
- 유튜브
- 깃헙
- DAGGER
- 안스
- error
Archives
- Today
- Total
코딩하는 일용직 노동자
Hilt에서 @Provides와 @Binds: 언제, 어떻게 사용해야 할까? 본문
안드로이드 개발에서 Hilt를 사용하여 의존성 주입(Dependency Injection)을 할 때, 모듈(Module) 내에서 의존성을 제공하는 방법으로 `@Provides`와 `@Binds` 두 가지 애노테이션을 사용합니다.
둘 다 의존 객체를 제공하는 역할을 하지만, 사용 목적과 방식, 그리고 성능에서 차이가 있어 상황에 맞게 사용하는 것이 중요합니다.
결론부터 말하자면, 인터페이스(interface)와 구현체(implementation)를 묶어주는 단순한 작업에는 `@Binds`를, 복잡한 객체 생성 로직이 필요할 때는 `@Provides`를 사용하는 것이 좋습니다.
@Provides: 객체 생성의 모든 것을 책임진다
`@Provides`는 Hilt가 직접 생성할 수 없는 타입의 객체를 어떻게 만들어서 제공할지 알려주는 역할을 합니다.
다음과 같은 경우에 주로 사용됩니다.
- 외부 라이브러리 객체 생성:** Retrofit, OkHttpClient, Room 데이터베이스처럼 프로젝트 소스 코드에 속하지 않아 생성자에 `@Inject`를 추가할 수 없는 클래스의 인스턴스를 제공해야 할 때 사용합니다.
- 빌더 패턴(Builder Pattern) 사용:** 객체 생성을 위해 빌더 패턴을 사용해야 하는 경우, `@Provides` 함수 본문에 빌더를 통한 생성 로직을 구현할 수 있습니다.
- 인스턴스 생성 전 조건부 로직 필요:** 특정 조건에 따라 다른 구현체를 제공해야 하는 등 복잡한 로직이 필요한 경우에 유용합니다.
`@Provides` 함수는 반드시 **객체 생성 로직을 포함한 본문(body)을 가지며**, 보통 `object`로 선언된 모듈 안에 위치합니다.
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.build()
}
@Provides
@Singleton
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
}
@Binds: 인터페이스와 구현체를 연결하는 가장 효율적인 방법
`@Binds`는 **인터페이스에 대한 구현체를 Hilt에게 알려주는, 보다 전문화되고 효율적인 방법**입니다. 특정 인터페이스가 요청될 때 어떤 구현체를 주입해야 할지 지정하는 역할을 합니다.
`@Binds`를 사용하기 위한 몇 가지 제약 조건이 있습니다.
- 추상(abstract) 클래스 모듈:** `@Binds` 함수는 반드시 추상 클래스(abstract class)로 선언된 모듈 안에 위치해야 합니다.
- 추상(abstract) 함수:** 함수 자체도 추상 함수여야 하며, 본문을 가질 수 없습니다.
- 단일 파라미터:** 함수는 반드시 하나의 파라미터를 가져야 하며, 이 파라미터가 바로 주입될 구현체입니다.
`@Binds`는 단순히 "이 인터페이스가 필요하면 저 구현체를 사용해"라고 알려주기만 하므로, Hilt가 더 적은 양의 코드를 생성하게 됩니다.
interface UserRepository {
fun getUser(): User
}
class UserRepositoryImpl @Inject constructor(
private val remoteDataSource: UserRemoteDataSource
) : UserRepository {
override fun getUser(): User {
return remoteDataSource.fetchUser()
}
}
@Module
@InstallIn(ViewModelComponent::class)
abstract class RepositoryModule {
@Binds
abstract fun bindUserRepository(
userRepositoryImpl: UserRepositoryImpl
): UserRepository
}
@Provides vs. @Binds: 성능 차이는 왜 발생할까?
가장 큰 차이점은 **코드 생성량과 런타임 성능**입니다.
- @Provides:** Hilt는 `@Provides` 함수를 위해 별도의 팩토리(Factory) 클래스를 생성합니다.
의존성을 주입할 때마다 이 팩토리의 메소드를 호출하여 객체를 생성하므로, 약간의 런타임 오버헤드가 발생할 수 있습니다.
- @Binds:** `@Binds`는 Hilt에게 단순히 타입 정보만 알려줍니다.
Hilt는 이 정보를 바탕으로 별도의 팩토리 클래스 없이 의존성 그래프를 구성합니다.
결과적으로 생성되는 코드가 더 적고 간결하며, 런타임 시 메소드 호출이 줄어들어 더 효율적입니다.

따라서 인터페이스와 그 구현체를 1:1로 바인딩하는 경우에는 성능상의 이점을 위해 항상 `@Binds`를 사용하는 것이 권장됩니다.
`@Provides`로도 동일한 기능을 구현할 수 있지만, 불필요한 오버헤드가 발생하게 됩니다.
'안드로이드' 카테고리의 다른 글
| Hilt, 5분 만에 정복하기 (feat. 배달 서비스 비유) (0) | 2025.12.14 |
|---|---|
| 안드로이드 클린 아키텍처, 쉽게 이해하기. (0) | 2025.12.14 |
| LaunchedEffect, DisposableEffect, LifecycleEventEffect, LifecycleStartEffect, LifecycleResumeEffect 정리 (2) | 2025.08.10 |
| Android 프로젝트에 ktlint + Spotless 적용하기 (2) | 2025.07.27 |
| 맥북(Mac) 안드로이드 usb 테더링 설정하기 (0) | 2025.06.29 |