# Binding?
flowchart LR
Android -->|Compile, Request| Hilt
Hilt -->|Runtime, Inject| Android
AppModule ---> Hilt
NetworkModule ---> Hilt
์์กด์ฑ์ ์ถ๊ฐํ๋ ํ์๋ ๊ฐ๋ณ์ ์ธ ์ธ์คํด์ค dependency(Inject๋ก ๋์ด์๋) ๋ชจ๋ ๋ฐ์ธ๋ฉ์ด๋ผ๊ณ ํ๋ค. ๊ทธ๋ฅ ์์กด์ฑ์ ๋ฐ๋ก ๊ฝ์ ์๋ ์๊ณ , ์์กด์ฑ์ ๊ด๋ฆฌํ ๋ชจ๋์ ๋ฌ์ ๋ชจ๋์ HiltComponent์ ๊ฝ์ ์ฌ์ฉํ๊ธฐ๋ ํ๋ค.
# Dependency Injection - ์์ฑ์ ์ฃผ์ , ํ๋ ์ฃผ์ , ๋ฉ์๋ ์ฃผ์
// ์์ฑ์ ์ฃผ์
class Test @Inject constructor(foo: Foo){ // foo ์ฃผ์
๊ณผ ๋์์ Test ๋ฐ์ธ๋ฉ
}
// ํ๋ ์ฃผ์
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject // ์๋ ์์ฒญํด์ ์ฃผ์
๋ฐ๋ ๊ฒ
lateinit var test: Test
...
}
// ๋ฉ์๋ ์ฃผ์
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
fun foo(bar: Bar){
...
}
์์ฑ์ ์ฃผ์ ๊ณผ ํ๋์ฃผ์ ์ ์ด์ ๊ฒ์๊ธ์์ ํ์ธํ๋ค. ๋ฉ์๋ ์ฃผ์ ๋ง ๋ณด๋ฉด ๋๋๋ฐ, foo ๋ฉ์๋๋ bar๋ผ๋ ํ๋ผ๋ฏธํฐ์ ์์กด์ฑ์ ์ฃผ์ ๋ฐ๊ฒ ๋๋ค.
์์ฑ์ ์ฃผ์ ์ ๋ฐ๋ก ์ค์ฝํ ์์ด Injectํด๋ฒ๋ฆฌ๋๋ฐ ์ด ๊ฒฝ์ฐ Test ํด๋์ค ์์ฒด๋ ์ปดํ์ผ ํ์์ Hilt ์ปดํฌ๋ํธ์ ๋ฐ์ธ๋ฉ๋๋ค๋ ํน์ด์ ์ด ์๋ค. ๋ฉ์๋ ์ฃผ์ ์ Inject๊ฐ `super.onCreate` ์ดํ์ ์๋ํ๊ธฐ ๋๋ฌธ์ ์ด ๋ฉ์๋์์ lateinit var๋ฅผ ์ด๊ธฐํํ ์ ๋ ์๋ค.
lateinit var fooFun: Foo
@Inject // method ์ฃผ์
fun provideFoo(foo: Foo){ // super.onCreate ์ดํ์ Inject๋์ด fooFun์ ์ด๊ธฐํ ๋ ์ํ๋ก ์ ๊ทผ๊ฐ๋ฅํ๋ค.
fooFun = foo
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
assert(this::fooFun.isInitialized) // true์ด๊ธฐ ๋๋ฌธ์ crash ๋ฐ์ํ์ง ์์
...
}
๊ทผ๋ฐ ๋ชจ๋์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋ฉ์๋ ์ฃผ์ ์ ์๋ฌด๋๋ ์ฌ์ฉํ๋ ๋น๋๊ฐ ์ ์ ๊ฒ ๊ฐ๋ค.
# `@Qualifier` , `@Named("์๋ณ๋ช ")`
Hilt๋ ํ์ ์ ๊ธฐ์ค์ผ๋ก ์์กด์ฑ์ ๊ตฌ๋ถํ๋๋ฐ ๊ทธ๋์ ์ค๋ณต ๋ฐ์ธ๋ฉ์ด ๋ฐ์ํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค. ๋์ผํ ํ์ ์ ๋ ์์กด์ฑ์ ๊ตฌ๋ถํ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ด๋ค. -> `Dagger/DuplicateBindings` ๋ก ์๋ฌ๊ฐ ๋์จ๋ค. ๊ทผ๋ฐ ํ์ ์ ๋์ผํ์ง๋ง ์ญํ ์ด ๋ค๋ฅธ ๊ฒฝ์ฐ ๋ ๊ฐ์ง ๋ชจ๋ ์ด๋ ค์ผํ ๋๊ฐ ์๋ค. ์๋ฅผ ๋ค๋ฉด Access Token์ผ๋ก ์ ๊ทผํด์ผ ๋๋ ์์กด์ฑ๊ณผ ๊ทธ๊ฒ ์์ด๋ ์ ๊ทผ ๊ฐ๋ฅํ ์์กด์ฑ ์ด๋ ๊ฒ ๋๊ฐ๋ก ๋๋ ๋๊ฐ ๊ทธ ์์๋ค. ์ด ๊ฒฝ์ฐ Qualifier๋ก ๊ตฌ๋ถํ ์ ์๋ค.
์ฌ์ฉ ๋ฐฉ๋ฒ์ ์๊ทผํ ๊ฐ๋จํ๋ค.
@Qualifier
annotation class TestQualifier
@Module
@InstallIn(SingletonComponent::class)
object TestModule {
@Provides
fun provideTest(): Test {
return Test(id = "Test")
}
@TestQualifier
@Provides
fun provideTest2(): Test {
return Test(id = "TestQualifier")
}
}
Qualifer ์ด๋ ธํ ์ด์ ์ ๋ฌ๊ณ ์๋ ์ปค์คํ Qualifier annotation์ ๋ง๋ค๊ณ , ๊ทธ๊ฑธ ์ค๋ณต๋ฐ์ธ๋ฉ์ด ํ์ํ ๊ณณ์ ๋ฌ์์ฃผ๋ฉด ๋๋ค.
@Inject
lateinit var test1: Test
@TestQualifier
@Inject
lateinit var test2: Test
// ๋ฉ์๋ ์ฃผ์
์ ๊ฒฝ์ฐ
@Inject
fun injectTest(@TestQualifier test: Test){
testQualifier = test
}
๋ฌผ๋ก ์ฃผ์ ๋ฐ์ ๊ณณ์๋ ๋ฌ์์ค์ผ๋๋ค.
๊ป๋ฐ๊ธฐ๋ง ๋ง๋ค์ด๋๊ณ ์ฌ์ฉํ ์๋ ์์ง๋ง ์์ฑ์ ์ ์ํ๋ ๋ฐฉ์์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ๋ ๊ฐ๋ฅํ๋ค.
@Qualifier
annotation class TestQualifier(val id: String)
์ด๋ ๊ฒ ์ ์ํ๋ฉด Inject๋ ๋ฐ์ธ๋ฉ ํ ๋ ์์ฑ๊ฐ์ธ key๋ฅผ ๋ช ์ํด์ค์ผํ๋ค.
์ด๋ฐ ์๋ณ๊ณผ์ ์ ์ข ๋ ์ฝ๊ฒํ๋ ๋ฐฉ๋ฒ์ด `@Named`์ธ๋ฐ ์๋ณ๋ช ๋ฌธ์์ด์ id๋ก ๊ฐ๋ Qualifier๋ผ๊ณ ๋ณด๋ฉด ๋ ๊ฒ ๊ฐ๋ค.
@Module
@InstallIn(SingletonComponent::class)
object TestModule {
// @TestQualifier
@Named("Test")
@Provides
fun provideTest2(): Test {
return Test(id = "TestQualifier")
}
}
ํ ๋ฐ ๋ชจ์ ๊ด๋ฆฌํ๊ธธ ์ข์ํ๋ ์ฌ๋๋ค์ ์๋ง Named ๋ณด๋ค Qualifier๋ฅผ ์ ํธํ์ง ์์๊น ์๊ฐํ๋ค.
# Lazy์ Provider
Hilt์ Lazy ์ฃผ์ ์ by lazy๊ณผ ํน์ ์์ ์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค๋ ์ ์์ ์ฝ๊ฐ ๋น์ทํ๋ค. ์ธ์คํด์ค ์์ฑ์์ ์ ์กฐ์ ํ๋ค๋ ์๋ฏธ๋ ์์ฑ๋น์ฉ์ด ์ปค์ ์ด๊ฑธ ์กฐ์ ํ๊ฒ ๋ค๋ ์๋ฏธ๋ ๋ ์ ์๋ค.
@Inject
lateinit var foo: Lazy<Foo> // Lazy
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
assert(foo.get().bar != null)
get์ผ๋ก Lazy ์ฃผ์ ์ ๋ฐ์์ฌ ์ ์๋๋ฐ, ์ฃผ์ํ ์ ์ Lazy๊ฐ dagger ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํ์ ์ด๋ผ๋ ๊ฒ์ด๋ค. ์ฝํ๋ฆฐ๋ Lazy๋ฅผ ๊ฐ๊ณ ์๊ธฐ ๋๋ฌธ์ import๋ฅผ ์๋ชปํ๋ฉด get์ผ๋ก ๋ชป๊ฐ์ ธ์จ๋ค.
Lazy๋ก ์ ์ธํ ์ธ์คํด์ค๋ ํ๋ฒ ์ฃผ์ ๋๋ฉด ๊ฐ์ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋ค.
@Inject
lateinit var fooProvider: Provider<Foo>
Provider๋ ๋น์ทํ๋ค. get์ผ๋ก ๊ฐ์ ธ์ค๊ณ , ํธ์ถํ ๋ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค. Lazy์ ๋ค๋ฅธ ์ ์ Lazy๋ ํ๋ฒ ์์ฑ๋๋ฉด ๊ทธ๊ฑธ ๊ฐ์ ธ์ค๋ ๊ฑฐ๊ณ , Provider๋ ๋งค ํธ์ถ๋ง๋ค ์ ์ธ์คํด์ค๋ฅผ ๊ฐ์ ธ์จ๋ค. ๊ทธ๋์ ๊ฐ ํธ์ถ์ ๋ํด ๋์ผํ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๊ณ ์ถ๋ค๋ฉด Scope๋ฅผ ์ง์ ํด์(`@Singleton`์ ๋ถ์ธ๋ค๋๊ฐ) ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ ํํด์ผ๋๋ค.
# ๋ฐ์ธ๋ฉ ๊ธฐ๋ฒ - `@Binds`
๋ฐ์ธ๋ฉ์ DI ๊ทธ ์์ฒด(์ปดํฌ๋ํธ์ ์์กด์ฑ์ ์ถ๊ฐํ๋ ํ์) ๋๋ ๊ทธ ์์กด์ฑ ์์ฒด๋ฅผ ์๋ฏธํ๋ค.
๋ชจ๋ ์์์ ์ปดํฌ๋ํธ์ ๋ฌ์๋๋ `@Provides`๋ ์ด์ ์ต์ํด์ก๋ค. ๊ธฐ์กด์ Provide ๋ ๋ฐ์ธ๋ฉ์ด ์์ผ๋ฉด `@Binds`๋ก ํจ์จ์ ์ผ๋ก ๋ฌ์ ๋ ์ ์๊ฒ ๋๋ค. Binds๊ฐ ์ค์ํ ์ด์ ๋ ์ธ์ด ํน์ฑ์ ์ธํฐํ์ด์ค ํ์ ์ผ๋ก ์ ์ธ๋ ๋ณ์์ ํ์ ํ์ ์ผ๋ก ๋ฐ์ธ๋ฉ์ ๊ฑธ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ฆ `@Binds`๋ ์ด๋ฏธ ๋ฐ์ธ๋ฉ ๋ ์์กด์ฑ์ ํ์ฅ๊ด๊ณ์ ์๋ ์ ํ์ ์ผ๋ก ๊ฐ์ธ์(์ ํ์ ์ผ๋ก ๋ชจ๋ ์ค์น๊ฐ ๊ฐ๋ฅํ๋ค) ๋ฐ์ธ๋ฉ ์ํฌ ๋ ํจ์จ์ ์ผ๋ก ๋์ํ๋ค. ๋ฐ๋ผ์ ์ ์ฝ ์กฐ๊ฑด์ด ์กด์ฌํ๋๋ฐ,
- `@Binds`๋ ๋ชจ๋ ๋ด abstract ๋ฉ์๋์ ์ถ๊ฐ๋ผ์ผํ๋ค.
- ํ๋ผ๋ฏธํฐ๋ฅผ ํ ๊ฐ๋ง ๊ฐ์ง ์ ์๋ค.
- ํ๋ผ๋ฏธํฐ ํ์ ์ด ๋ฐํ ํ์ ์ ์๋ธํ์ ์ด์ด์ผ ํ๋ค.
- `@Scope` ๋ฐ `@Qualifier` ๋ ๊ฐ์ด ์ธ ์ ์๋ค.
1, 2, 3 ๋ชจ๋ ํ์ฅ์ด ์ฉ์ดํ ์ธ์ดํน์ฑ์ ๊ทธ๋๋ก ๋ฐ์ํ ์กฐ๊ฑด๋ค์์ ์ ์ ์๋ค.
abstract ๋ฉ์๋๋ ๊ตฌํ์ฒด๊ฐ ํ์ํ ๊ฒฝ์ฐ๋ผ ์ด๊ฒ๋ง์ผ๋ก๋ ์ธ์คํด์ค๋ฅผ ์์ฑํ ์ ์๋๋ฐ, provides๋ ๊ทธ๊ฒ ์๋๊ธฐ ๋๋ฌธ์ ์ฃผ์ํด์ผ๋๋ค.(ํ์ผ ์์ฒด๋ฅผ ๋ถ๋ฆฌ ์์ผ๋ฒ๋ฆฌ๋ ๊ฒ ์ข๋ค.) ๋ค์ด๋ฐ๊ท์น์ `bind์๋ธํ์ `์ผ๋ก ์์ํ๋ค.
@Module
@InstallIn(SingletonComponent::class)
// Binds๋ฅผ ์ํ ์ถ์ ๋ชจ๋์ ๋ง๋ค์ด ์ค๋ค
abstract class EngineModule {
@Binds
abstract fun bindGasolineEngine(engine: GasolineEngine): Engine
@Binds
abstract fun bindDieselEngine(engine: DieselEngine): Engine
}
Engine์ ์ธํฐํ์ด์ค๊ณ , GasolineEngine, DieselEngine์ ์์ฑ์ ๋ฐ์ธ๋ฉ์ผ๋ก ์ปดํฌ๋ํธ์ ๋ฌ๋ ค์๋ ์ํ๋ค. ์ด๋๋ก๋ง ๋๋๋ฉด Engine์ ๋ฐํํ๋ ๊ฒ ์ค๋ณต๋ผ์ ์ค๋ณต๋ฐ์ธ๋ฉ์ ํ์ฉํ์ง์๋ Hilt ํน์ฑ์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค. Named๋ Qualifier๋ก ํด๊ฒฐํ๋ฉด ๋๋ ๋ถ๋ถ์ด๊ธฐ ๋๋ฌธ์ ์ด๊ฑด ํ์์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ์ฌ์ฉํ๋ฉด ๋ ๊ฒ ๊ฐ๋ค.
# ์ต์ ๋ ๋ฐ์ธ๋ฉ `@BindsOptionalOf`
๋ฐ์ธ๋ฉ ๋์ด ์์ ์๋ ์๋ ์์กด์ฑ์ ์์ฒญํ๋ ์ด๋ ธํ ์ด์ ์ด๋ค. ์ต์ ๋์ด๊ธฐ ๋๋ฌธ์ ๋ฐ์ธ๋ฉ ๋์ง์์๋ ์ผ๋จ ์ปดํ์ผ ์๋ฌ๋ ๋ฐ์ํ์ง ์๋๋ค. ๋ฐ์ธ๋ฉ์ด ์๋ ๊ฒฝ์ฐ๋ ์์ ์ ์๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ณธ์ ์ผ๋ก ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ง๋ฉด ์๋๋ค. ๋ ๋ฐ์์ฌ ์์กด์ฑ๋ Optionalํด์ผ๋๊ธฐ ๋๋ฌธ์ ์์ฑ์ ๋ฐ์ธ๋ฉ ๋ ์์กด์ฑ๋ค์ ์ด๋ ์ฌ์ฉํ ์ ์๋ค.
@Provides
fun provideFoo(): Foo{
return Foo()
}
๊ทธ๋์ BindsOptionalOf๋ ๋ฐ๋ก provide๋ ์์กด์ฑ์ ๋ฌ์์ค์ผ๋๋ค.
@BindsOptionalOf
abstract fun bindDieselEngine(): Engine
์ด๋ ๊ฒ ํ๋ ๋ฐฉ๋ฒ ๋ง๊ณ ์์กด์ฑ ๊ทธ๋ํ ์์ ๊ด๊ณ์์ ๋ชจ๋ `Optional<T>`๋ก ์ ์ธํด์ฃผ๋ ๋ฐฉ๋ฒ๋ ์๋ค.
@Inject
lateinit var foo: Optional<Foo>
BindsOptionalOf๋ก ๋ฐ์ธ๋ฉ ๋ ์์กด์ฑ์ ์์ฒญํ ๋๋ Optional๋ก ๊ฐ์ธ์ ํด์ฃผ๊ณ , get()์ผ๋ก ๊ฐ์ ธ์จ๋ค.
๋ฐ์ธ๋ฉ ๋์ง์์๋ค๋ฉด ์์ธ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ isPresent๋ก ์ฒดํฌํด์ค์ผ๋๋ค.
`@BindsInstance`๋ ์ปดํฌ๋ํธ ์์ฑ๊ณผ ๋์์ ๋ฐ์ธ๋ฉ ๋๋ ๊ฑธ ๋งํ๋ค. ๊ทผ๋ฐ ์ด๊ฑด ๋ฐ๋ก ์ธ๋ถ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฉํ ๋ ์ฃผ๋ก ์ฌ์ฉํ๋ค...
๋์์ด ๋๋ค๋ฉด ๋๊ธ์ด๋ ๊ณต๊ฐ ๋ฒํผ ํ ๋ฒ์ฉ ๋๋ฅด๊ณ ๊ฐ์ฃผ์ธ์!
'Android ๐ฅ๏ธ > DI๐' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
@Provides ์ @Binds (0) | 2024.08.02 |
---|---|
Android 15 ๋์ ํ๋ก์ ํธ ๊ตฌ์กฐ ๋ณํ... ๊ทธ๋ฆฌ๊ณ toml์์๋ณด๊ธฐ + Hilt ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ถ๊ฐํ๊ธฐ (0) | 2024.07.16 |
Hilt(3) - ๋ฉํฐ ๋ฐ์ธ๋ฉ (0) | 2024.07.05 |
Hilt(1) (0) | 2024.06.22 |
DI ์ ๋ฌธ - ์ข ์ ํญ๋ชฉ ์ฝ์ (0) | 2024.03.07 |