-Hilt에서 의미하는 바인딩이란 어떠한 의존성을 Hilt Component에 추가 하는 행위 또는 해당 의존성을 일컫는 용어를 의미한다.
-@Inject는 의존성을 요청할 때에만 사용되는 것이 아니라 생성자에 마킹함으로서 해당 객체에 대한 의존성을 주입받을 뿐만 아니라 바인딩 또한 함께 실행된다.
-@Module이 마킹된 클래스 또는 object의 필드에 메서드를 선언한 이후에 @Provides를 마킹하면 Hilt Component에 메서드의 파라미터가 바인딩 된다.
-바인딩 되는 방식은 메서드의 반환값(Null 허용 X)이 바인딩 되는 형식으로 구성되어져 있다. Null을 허용하고 싶으면 BindsOptionalOf를 사용해야 한다.
-기존에 바인딩 되어진 의존성이 존재할 때 새로운 @Provide 메서드를 만들지 않고 효율적으로 바인딩 할 수 있도록 해준다.
interface Engine
class GasolineEngine @Inject constructor() : Engine
@Module
@InstallIn(SingletonComponent::class)
abstract class EngineModule {
@Binds
abstract fun bindEngine(engine : GasolineEngine) : Engine
}
-@Binds는 반드시 모듈 내부의 abstract 메서드에만 마킹이 가능하다.
-@Binds 메서드는 반드시 하나의 Parameter만 갖을 수 있다.
-Parameter 타입이 반환타입의 서브타입이여야 한다.
@Module
@InstallIn(SingletonComponent::class)
abstract class MyModule {
companion object{
@Provides
fun provideFoo() : Foo { }
}
@Binds
abstract fun bindssEngine(engine:GasolineEngine) : Engine
}
-바인딩이 확실히 되어있다는 보장이 없는 의존성을 요청할 때 사용한다.
-만약 Client가 Hilt-Component에 바인딩 되어있지 않은 의존성에 대한 주입을 요청한다면 컴파일 타임에 에러가 발생한다.
-그렇다면 Optional< T >를 클라이언트가 용청하면 컴파일 타임에서 에러가 발생하지 않도록 하는 방식을 사용 할 수 있다.
-Module 내부에서 @BindsOptionalOf를 설정하는 방법 예시코드 + 설명
@Module
@InstallIn(SingletonComponent::class)
abstract class FooModule {
@BindsOptionalOf
abstract fun optionalFoo() : Foo
}
-@BindsOptionalOf가 마킹된 메서드를 통해 의존성을 주입받는 방법 예시코드 + 설명
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject
lateinit var optionalFoo : Optional<Foo>
}
class Bar @Inject constructor(
optionalFoo : Optional<Foo>
)
@Provides
fun provideString(
optionalFoo : Optional<Foo>
) : String {
}
-isPresent()
-get()
-Hilt-Componet의 생성과 동사에 바인됭 된다.
-멀티 바인딩이 의미하는 것은 여러가지의 의존성을 하나의 컬렉션으로 관리하는 것을 의미한다.
-Collection 자체를 Hilt-Component에 바인딩하는 기법이라는 의미이다. Hilt에서는 Set과 Map을 통해서 MultiBinding을 구현 할 수 있다.
-멀티 바인딩을 사용해서 동일한 타입의 여러 객체들을 한 번에 관리하고 주입할 수 있다는 장점이 있다.
-동일한 타입의 의존성들을 Set 형태로 관리하는 것을 의미한다.
-@Provides가 마킹된 메서드에 @IntoSet을 마킹해서 멀키 바인딩을 적용 할 수 있다.
-@IntoSet을 추가하면 컴파일 타임에 Hilt-Component 내부에 Set을 하나 생성하고 Set의 제너릭 타입인 의존성들을 추가할 수 있는 환경을 만들어 준다.
@Module
@InstallIn(SingletonComponent::class)
class MyModuleA {
Provides
@IntoSet
fun provideOneString() : String {
return "ABC"
}
}
-요소들을 통째로 Set 타입 객체로 멀티바인딩 할 수 있다. @Provides가 마킹된 메서드에 @ElementsIntoSet을 마킹해서 멀티 바인딩을 적용 할 수 있다.
@Module
@InstallIn(SingletonComponent::class)
class MyModuleB {
@Provides
@ElementsIntoSet
fun provideTwoString() : Set<String> {
return listOf("DEF" , "GHI").toSet()
}
}
class Bar @Inject constructor(
val strings : Set<String>
) {
init{
assert(strings.contatins("ABC"))
assert(strings.contatins("DEF"))
assert(strings.contatins("GHI"))
}
}
-Map 자료구조는 키와 value 관계로 구성되어 있다. 따라서 Map을 사용한 멀티바인딩에서는 의존성과 관계를 맺을 key가 반드시 필요하다.
-각각 상황에 맞게 알맞은 키를 선택해서 사용하면 된다.
-@StringKey
-@IntKey
-@LongKey
-@ClassKey
-바인딩 할 때 Key를 명시적으로 지정을 해야한다.
@Module
@InstallIn(SingletonComponent::class)
object MyModule {
@Provides
@IntoMap @StringKey("foo)
fun provideFooValue() : Long {
return 100L
}
@Provides
@IntoMap @ClassKey(Bar::class)
fun provideBarValue() : String {
return "value for Bar"
}
}
-주입 할 때는 제너릭 타입으로 주입되므로 신경써서 주입해야 한다. 주입한 Map에 Key값을 넣어서 값을 가져올 수 있다.
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject
lateinit var map1 : Map<String , Long>
@Inject
lateinit var map2 : Map<Class< * > , String>
override fun onCreate(savedInstanceState : Bundle?) {
super.onCreate(savedInstanceState)
map1["foo"].toString
map2[Bar::class.java]
}
}
-@MapKey라는 어노테이션을 활요해서 커스텀 키를 만들어서 멀티바인딩에 사용 할 수 있다.
-1단계 : enum class로 키 모임 만들기
enum class MyEnum {
ABC,
DEF
}
-2단계 : @MapKey 어노테이션을 사용해서 위에서 만든 enum class를 키로 활용 할 수 있도록 커스텀한 어노테이션을 만든다.
@MapKey
annotation class MyEnumKey(val value : MyEnum)
-3단계 : 멀티 바인딩하기
@Module
@InstallIn(SingletonComponent::class)
object MyModule {
@Provides
@IntoMAp
@MyEnumKey(MyEnum.ABC)
fun provideABCValue() : String {
return "value for ABC"
}
@Provides
@IntoMAp
@MyEnumKey(MyEnum.DEF)
fun provideABCValue() : String {
return "value for DEF"
}
}
-4단계 : 의존성 주입받기
-주입 할 때는 제너릭 타입으로 주입되므로 신경써서 주입해야 한다.주입한 Map에 enum class에서 만든 Key값을 넣어서 값을 가져올 수 있다.
class MainActivity : ComponentActivity() {
@Inject
lateinit var map : Map<MyEnum , String>
override fun onCreate(savedInstanceState : Bundle) {
super.onCreate(savedInstanceState)
map[MyEnum.ABC]
map[MyEnum.DEF]
}
}