[Android, Kotlin] Hilt에서 @Binds와 @Provides의 차이점
Android

[Android, Kotlin] Hilt에서 @Binds와 @Provides의 차이점

Android에서 * DI (의존성 주입)를 도와주기 위한 라이브러리인 Hilt를 학습하여 사용 중이다.

 

* DI : https://hungseong.tistory.com/10

 

DI(Dependency Injection), 의존성 주입

Dependency 의존성 함수에 필요한 클래스, 객체 등에 의존하는 것. 한 객체가 다른 객체를 참조(다른 객체와 상호작용)하는 것 위 같은 코드에서 DefaultRestaurantFoodRepository 클래스는 FoodApiService에 종..

hungseong.tistory.com

 

 

(1) constructor inject

 

 

Hilt를 사용 하면서, 다음과 같이 프로젝트 내에서 클래스의 인스턴스를 Hilt에게 바로 제공 할 수 있는 경우에는 따로 Module을 통해 Install 하지 않고 constructor inject을 통해 종속성을 제공해 줄 수 있다.

 

class DateFormatter @Inject constructor() {

    @SuppressLint("SimpleDateFormat")
    private val formatter = SimpleDateFormat("d MMM yyyy HH:mm:ss")

    fun formatDate(timestamp: Long): String {
        return formatter.format(Date(timestamp))
    }
}



// DateFormatter Inject하여 사용

@AndroidEntryPoint
class LogFragment : Fragment() {

    @Inject lateinit var dateFormatter: DateFormatter
    ...
}

 

그러나 Room, Retrofit과 같은 외부 라이브러리에서 제공되는 클래스이므로 프로젝트 내에서 소유할 수 없는 경우 또는 constructor를 가질 수 없는 인터페이스에 대한 종속성 삽입의 경우에는 위와 같은 constructor-inject를 통해 종속성을 제공할 수 없다.

 

이 때 Hilt Module을 추가하여 종속성을 제공 할 수 있는데, 제공해야 하는 종속성의 종류에 따라 @Binds와 @Provides로 나뉘게 된다.

 

 

 

(2) @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이어야 한다.

 

 

(3) @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 된 코드로 제공된다.

 

 

 

참고 : 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

 

 

https://3edc.tistory.com/67

 

[Android] Hilt @Binds, @Providers 차이점

Android에서 의존성 주입(DI / Dependency Injection)을 도와주기 위해서 Hilt 라이브러리를 제공해 줍니다. Hilt 라이브러리를 사용하면 의존성 주입을 위해 Android 프로젝트에 컨테이너를 제공하고 수명 주

3edc.tistory.com