-
Android 의존성 주입 Hilt - 3개발 2023. 7. 4. 10:06
Bind와 Provider의 차이
생성자 주입이 불가능한 경우 Hilt Module을 추가하여 종속성을 제공 할 수 있는데, 제공해야 하는 종속성의 종류에 따라 @Binds와 @Provides로 나뉘게 된다.
@Binds
@Binds는 constructor를 가질 수 없는 인터페이스에 대한 종속성 삽입의 경우에 사용한다.
// 인터페이스 interface LogRepository { suspend fun add(msg: String) suspend fun getLogs() : List<Log> } // 인터페이스 구현체 @Singleton class LogDBRepository @Inject constructor(private val logDao: LogDao, private val ioDispatcher : CoroutineDispatcher) : LogRepository { override suspend fun add(msg: String) = withContext(ioDispatcher) { logDao.add(Log(msg = msg)) } override suspend fun getLogs(): List<Log> = withContext(ioDispatcher) { logDao.getLogs() } }다음과 같이 LogRepository 인터페이스를 구현하는 class는 다른 class에서 종속성이 주입되어 사용 시 LogRepository라는 인터페이스 타입을 가지게 된다.
@HiltViewModel class LogViewModel @Inject constructor(@LogDB private val logRepository: LogRepository) : ViewModel() { ... }LogRepository에 대한 constructor-inject 종속성 주입은 interface이므로 불가능하다. 이 때 Module을 생성하여 @Binds 어노테이션을 사용할 수 있다.
@InstallIn(SingletonComponent::class) @Module abstract class LogDBModule { @Binds @Singleton abstract fun bindLogDBRepository(impl: LogDBRepository) : LogRepository }위와 같이 @Binds 어노테이션을 통해 LogRepository에 대한 종속성을 제공할 수 있다.
이 때, 함수의 반환 타입은 구현하고자 하는 interface type이며, 매개변수는 실제 제공하고자 하는 interface의 구현체 class이다.
@Binds 어노테이션을 사용하기 위해서는 모듈은 abstract class, 함수는 abstract function이어야 한다.
@Provides
@Provides는 Room, Retrofit과 같은 외부 라이브러리에서 제공되는 클래스이므로 프로젝트 내에서 소유할 수 없는 경우 또는 Builder 패턴 등을 통해 인스턴스를 생성해야 하는 경우에 사용한다.
// Room Database @Database(entities = [Log::class], version = 1, exportSchema = false) abstract class AppDatabase : RoomDatabase() { abstract fun logDao(): LogDao } // Use val db = Room.databaseBuilder(context, Appdatabase::class.java, "name.db").build()Room을 예시로 들 때, db를 생성 할 때 외부 라이브러리인 Room 내에서 builder 패턴을 이용하므로 constructor-inject를 통한 종속성 주입이 불가능하다. 이 때 @Module을 생성하여 @Provides 어노테이션을 사용할 수 있다.
@InstallIn(SingletonComponent::class) @Module object DBModule { @Provides @Singleton fun provideDatabase(@ApplicationContext context: Context) : AppDatabase { return Room.databaseBuilder( context, AppDatabase::class.java, "logdata.db" ).build() } }이 때, 함수의 반환 타입은 제공하고자 하는 인스턴스의 type이며, 매개변수는 인스턴스 생성에 필요한 종속성, 함수 내부는 실제 인스턴스의 구현이다.
@Provides만 포함되는 Module의 경우 object 형태로 생성 했을 때 provider는 최적화 된 코드를 제공하며, inline 된 코드로 제공된다.

Bind로 마이그레이션하기
글을 정리하다 보니 인터페이스의 경우 구현해야할 대상의 생성자 주입이 많을수록 바인드로 작성하는게 유리하다는 판단이 들었다. 마찬가지로 구현체의 생성자가 DI 주입대상이 아닌경우(di를 통해 주입을 하는게 아니라 동적으로 생성되는 경우) 라면 당연히 binds를 사용할수 없다. (컴파일타임에 해당 객체가 주입이 안되므로..)

위처럼 location 은 컴파일타임에 주입될수없다. 이런경우 @Provides로 제공해야한다.
참고 : https://github.com/googlecodelabs/android-hilt
GitHub - googlecodelabs/android-hilt
Contribute to googlecodelabs/android-hilt development by creating an account on GitHub.
github.com
https://developer.android.com/training/dependency-injection/hilt-android
Hilt를 사용한 종속 항목 삽입 | Android 개발자 | Android Developers
Hilt를 사용한 종속 항목 삽입 Hilt는 프로젝트에서 수동 종속 항목 삽입을 실행하는 상용구를 줄이는 Android용 종속 항목 삽입 라이브러리입니다. 수동 종속 항목 삽입을 실행하려면 모든 클래스
developer.android.com
'개발' 카테고리의 다른 글
com.google.firebase.provider.FirebaseInitProvider: android.content.pm.PackageManager$NameNotFoundException 오류 (0) 2023.08.09 안드로이드 스튜디오 sha1 인증키 구하기 (0) 2023.08.03 외부라이브러리 proguard 설정 (0) 2023.07.12 Compose에서 Android UI계층 포함하기 (0) 2023.07.06 Room DB에서 Flow를 사용하여 DB 변경 관찰하기 (0) 2023.07.03