의존성(Dependency)이란 클래스가 다른 클래스 또는 객체에 의존하는 관계를 의미한다.
예를 들어, UserRepository
클래스가 ApiService
객체를 필요로 한다면, UserRepository
는 ApiService
에 의존성을 갖는다고 볼 수 있다.
class UserRepository {
private val apiService = ApiService()
}
위 코드는 UserRepository
가 ApiService
를 직접 생성(new
)하고 있어 강한 결합이 발생한다.
만약 ApiService가 없어지거나 파라미터 변경이 생기면 UserRepsitory 까지 영향이 전달된다.
의존성 주입(DI)은 객체를 직접 생성하는 것이 아니라 외부에서 주입받는 방식을 의미한다.
즉, UserRepository
가 ApiService
를 직접 생성하지 않고, 외부에서 제공하도록 설계하는 것이다.
class UserRepository(private val apiService: ApiService) {
fun getUser() = apiService.fetchUser()
}
이렇게 하면 UserRepository
가 ApiService
의 생성 방식에 대해 알 필요가 없고, 테스트할 때 Mock 객체를 쉽게 주입할 수 있어 유연성이 높아진다.
이런 식으로 의존성 주입을 설정하면, 제어의 역전이 이루어진다.
제어를 나타내는 화살표의 방향이 역전이 된 것을 확인할 수 있다.
이는 개발자가 직접 의존성을 제어하던 것을, 어떠한 매개체에게 제어권을 일임하여 더이상 제어의 주체가 개발자가 아니게 되는 것이라고 보면 된다.
Hilt는 Dagger 기반의 안드로이드 DI 라이브러리로, 구글이 공식 지원하며 의존성 관리를 단순화할 수 있도록 도와준다.
기존 Dagger보다 설정이 간단하며, @HiltAndroidApp
, @Inject
, @Module
, @Provides
, @Binds
등의 어노테이션을 활용해 의존성을 쉽게 주입할 수 있다.
build.gradle (Project)
에 아래 설정을 추가한다.
plugins {
id 'com.google.dagger.hilt.android' version '2.x.x' apply false
}
build.gradle (Module)
에 다음 의존성을 추가한다.
plugins {
id 'com.google.dagger.hilt.android'
}
dependencies {
implementation "com.google.dagger:hilt-android:2.x.x"
kapt "com.google.dagger:hilt-android-compiler:2.x.x"
}
@HiltAndroidApp
적용Application
클래스에 @HiltAndroidApp
을 추가하면 Hilt가 앱 전체에서 의존성을 관리할 수 있도록 설정된다.
@HiltAndroidApp
class MyApplication : Application()
@Inject
를 사용한 의존성 주입Hilt는 생성자 주입(Constructor Injection)을 지원한다.
즉, @Inject
를 생성자에 붙이면 Hilt가 자동으로 객체를 주입해 준다.
class UserRepository @Inject constructor(private val apiService: ApiService) {
fun getUser() = apiService.fetchUser()
}
위처럼 UserRepository
에 @Inject
를 추가하면, ApiService
객체를 Hilt가 알아서 주입해 준다.
@Provides
vs @Binds
모듈 사용법Hilt에서는 객체를 제공하는 방법으로 @Provides
와 @Binds
를 사용할 수 있다.
@Provides
사용 (객체 직접 생성)@Provides
는 객체를 직접 생성하여 반환할 때 사용한다.
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
@Provides
@Singleton
fun provideDatabase(
@ApplicationContext context: Context,
): PassionDailyDatabase =
Room.databaseBuilder(
context,
PassionDailyDatabase::class.java,
"passion_daily.db"
).build()
@Provides
@Singleton
fun provideUserDao(database: PassionDailyDatabase): UserDao = database.userDao()
}
@Binds
사용 (인터페이스와 구현체 연결)@Binds
는 인터페이스와 구현체 간의 관계를 설정할 때 사용한다.
단, @Binds
를 사용하려면 구현체에 @Inject
생성자가 필요하다.
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
@Binds
abstract fun bindLocalFavoriteRepository(
repository: LocalFavoriteRepositoryImpl
): LocalFavoriteRepository
}
@Inject
로 자동 주입 가능한 경우사진 및 참고 출처)
https://www.youtube.com/watch?v=1vdeIL2iCcM