Hilt는 안드로이드에서 의존성 주입(DI, Dependency Injection)을 쉽게 구현할 수 있도록 도와주는 라이브러리입니다.
Hilt를 사용하면 의존성 관리를 더욱 효율적으로 할 수 있으며, 코드가 간결해집니다.
특히 @Inject와 @Module, @Provides는 Hilt에서 가장 중요한 개념 중 하나입니다.
이번 글에서는 이 두 개념을 정리해보겠습니다.
@Inject: 직접 만든 클래스의 의존성 주입
@Inject는 직접 만든 클래스의 의존성을 Hilt가 자동으로 관리할 수 있도록 도와줍니다.
@Inject constructor를 사용한 생성자 주입
class ExampleRepository @Inject constructor() {
fun getData(): String = "Hello from Repository"
}
위처럼 @Inject를 클래스의 생성자에 붙이면, Hilt가 ExampleRepository를 의존성 그래프에 자동 등록해줍니다.
이렇게 하면 다른 클래스에서 ExampleRepository를 쉽게 주입받을 수 있습니다.
@Inject를 활용한 필드(Field) 주입
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
@Inject
lateinit var repository: ExampleRepository
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_example)
val data = repository.getData()
Log.d("ExampleActivity", data)
}
}
Hilt는 @Inject를 확인하고 ExampleRepository를 자동으로 주입합니다.
@Inject를 활용한 함수(Function) 주입
class ExampleClass {
lateinit var repository: ExampleRepository
@Inject
fun injectRepository(repository: ExampleRepository) {
this.repository = repository
}
}
Hilt는 injectRepository() 함수가 호출될 때 자동으로 ExampleRepository 객체를 주입합니다.
@Inject를 사용하면 좋은 경우
- 직접 만든 클래스라서 Hilt가 생성할 수 있는 경우
- 별도의 설정 없이 간단하게 의존성을 주입하고 싶을 때
@Module과 @Provides: 외부 라이브러리의 의존성 주입
외부 라이브러리(Retrofit, Room, SharedPreferences 등)는 @Inject를 직접 붙일 수 없습니다.
이런 경우 @Module과 @Provides를 사용하여 Hilt에 의존성을 제공해야 합니다.
@Module, @InstallIn과 @Provides를 이용한 의존성 제공
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl("https://api.example.com/")
.build()
}
}
Hilt 동작 방식
- @Module을 사용하여 의존성을 제공하는 클래스를 정의합니다.
- @InstallIn(SingletonComponent::class)를 사용해 Hilt가 어느 범위에서 이 모듈을 사용할지 설정합니다.
- @Provides를 사용하여 의존성을 제공할 함수를 선언합니다.
- provideRetrofit()의 반환값(Retrofit)을 Hilt의 의존성 그래프에 등록합니다.
이제 Retrofit이 필요한 곳에서 @Inject를 사용하면 자동으로 주입됩니다.
class ApiService @Inject constructor(private val retrofit: Retrofit) {
fun fetchData() {
// retrofit 사용 가능
}
}
Hilt는 @Inject를 확인하고, @Module에서 제공한 Retrofit 객체를 찾아서 ApiService에 자동 주입합니다.
@Module과 @Provides를 사용해야 하는 경우
- Retrofit, Room, SharedPreferences 같은 외부 라이브러리를 주입할 때
- 생성자에서 직접 @Inject를 사용할 수 없는 경우 (예: Builder 패턴이 필요한 경우)
인터페이스의 구현체를 제공해야 할 경우는 @Binds를 활용하는 것이 더 적절합니다. @Provides는 구체적인 객체를 반환해야 하지만, @Binds는 인터페이스의 구현체를 지정할 때 사용됩니다.
@Inject vs @Module과 @Provides 정리
구분 | 사용 방법 | 사용해야 하는 경우 |
@Inject | @Inject constructor() | 직접 만든 클래스를 자동으로 주입할 때 |
@Inject | 필드 주입 (@Inject lateinit var) | 액티비티, 프래그먼트에서 주입할 때 |
@Inject | 함수 주입 (@Inject fun injectXXX()) | 특정 함수에서 주입이 필요할 때 |
@Module과 @Provides | @Module과 @Provides로 제공 | 외부 라이브러리 객체를 주입할 때 |
@Module + @Binds | @Binds를 사용해 구현체 제공 | 인터페이스의 구현체를 주입할 때 |
결론
- 직접 만든 클래스는 @Inject를 사용하면 자동으로 주입됩니다.
- 외부 라이브러리는 @Module과 @Provides를 사용하여 주입해야 합니다.
- @InstallIn을 사용해 Hilt가 어느 범위에서 이 모듈을 사용할지 설정해야 합니다.
- 인터페이스의 구현체를 주입할 때는 @Binds를 사용하는 것이 적절합니다.
- Hilt는 반환 타입을 기준으로 의존성을 찾아서 자동으로 주입해 줍니다.