์๋ ํ์ธ์ ๐
์ค๋์ ์๋๋ก์ด๋ Hilt์ ์ฌ์ฉ๋ฒ์ ๋ํด ์์๋ณด๋ ค๊ณ ํฉ๋๋ค.

Hilt๋ฅผ ์์ํ๊ธฐ ์ ์ ๋จผ์
์์กด์ฑ ์ฃผ์ ์ด๋ ๋ฌด์์ธ์ง ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์์กด์ฑ ์ฃผ์ (Dependency Injection)์ด๋?
์์กด์ฑ ์ฃผ์ ์ด๋ class์class ๊ฐ ์์กด์ฑ์ ๋ํ ์ฃผ์ ์ ์ธ๋ถ์์ ํจ์ผ๋ก์จ class ๊ฐ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ์ด
์ฝ๋์ ์์ ์ฑ์ ๋์ด๋ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ์ ์๋ฏธ ํฉ๋๋ค.
/** ์์กด์ฑ์ด ์ฃผ์
๋์ง ์์ ์ฝ๋ **/
class Foo(){
val noDI = NoDepedency()
fun somethingTodo() {
noDI.foo()
}
}
class NoDependency(){
fun foo()
}
์์กด์ฑ์ด ์ฃผ์ ๋์ง ์์ ์ฝ๋๋ ์ ์ฝ๋์ ๊ฐ์ด NoDepedency๋ผ๋ class๋ฅผ Foo์์ ์ฌ์ฉํ๊ธฐ ์ํด Foo class ๋ด๋ถ์์ ์์ฑํ๊ฒ ๋์ด
์ฝ๋์ ๊ฒฐํฉ๋๊ฐ ์ฆ๊ฐํ๊ฒ ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
/** ์์กด์ฑ์ด ์ฃผ์
๋ ์ฝ๋ **/
class Foo(private val di : Dependency) {
fun somethingTodo() {
di.foo()
}
}
class Dependency {
fun foo()
}
๋ฐ๋ฉด์ ์์กด์ฑ์ ์ฃผ์ ์์๋ ์ ์ฝ๋์ ๊ฐ์ด Foo์์ ์ฌ์ฉํ Dependency๋ผ๋ class๋ฅผ ์ธ๋ถ์์ ์ ๋ฌ๋ฐ์์ผ๋ก Dependency๋ผ๋ class์ ๊ฒฐํฉ๋๊ฐ ๋ฎ์์ง ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ( Dependency๋ฅผ ์์ ํ๊ฒ ๋์ด๋ Foo์์๋ ํ ์ผ์ด ์๋ค. )
DI์ ์ฅ์
- ๊ฐ๊ฐ์ด ๋ ๋ฆฝ๋์ด ์๊ธฐ ๋๋ฌธ์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ ์ ์ง๋ณด์์ ์ฉ์ดํ๋ค.
- Boilerplate code๋ฅผ ์ค์ผ ์ ์๋ค.
- ์ฝ๋์ ์ฌ์ฌ์ฉ์ฑ์ด ์ฆ๊ฐํ๋ค.
๊ทธ๋ ๋ค๋ฉด Hilt๋ ๋ฌด์์ผ๊น์?
Hilt๋?
class๋ฅผ ์ธ๋ถ์์ ์ฃผ์ ํ๊ธฐ ์ํด์๋ ์ธ์คํด์ค์ ๋ํ ์๋ช ์ฃผ๊ธฐ(์์ฑ~์๋ฉธ๋๊ธฐ๊น์ง)์ ๊ด๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
์ด๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌํด ์ฃผ๊ธฐํด์ฃผ๊ธฐ ์ํด Google์์๋ Dagger ๊ธฐ๋ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ง๋ค๊ฒ ๋์๋๋ฐ ๊ทธ๊ฒ์ด ๋ฐ๋ก
Dagger Hilt์ ๋๋ค.
์ฆ , ๊ฐ instance์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํด ์ฃผ์ด ์์กด์ฑ ์ฃผ์ ์ ๋ณด๋ค ์ฝ๊ฒ ๋ง๋ google์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ฌ์ฉ ๋ฐฉ๋ฒ์ ์ด๋ป๊ฒ ๋ ๊น์? ๐ค
Hilt๋ Annotaion์ ํตํด ์ฑ์ ์ค์ ํ๊ณ ์์กด์ฑ์ ์ฃผ์ ํฉ๋๋ค.
๊ฐ๊ฐ์ Annotaion๋ค๊ณผ ์ค๋ช ๋ฐ ์ฌ์ฉ๋ฒ์ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์์ํ๊ธฐ์ ์์ Hilt๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ ํ๋ก์ ํธ ์ค์ ๋ถํฐ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
build.gradle ์ค์
// Project
plugins {
...
id 'com.google.dagger.hilt.android' version '2.44' apply false // Hilt
}
// Module
plugins {
...
// Hilt
id 'kotlin-kapt'
id 'com.google.dagger.hilt.android'
}
dependencies {
...
// Hilt
implementation "com.google.dagger:hilt-android:2.44"
kapt "com.google.dagger:hilt-compiler:2.44"
implementation "androidx.activity:activity-ktx:1.6.1"
implementation "androidx.fragment:fragment-ktx:1.5.5"
}
@HiltAndroidApp
Hilt๋ Application ์๋ช ์ฃผ๊ธฐ๋ฅผ ๋ฐ๋ฅด๋ฉฐ ์ปดํ์ผ ๋จ๊ณ ์ DI์ ํ์ํ ๊ตฌ์ฑ์์๋ค์ ์ด๊ธฐํํ๊ธฐ ์ํด ์ด ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํฉ๋๋ค.
์ฆ, Hilt์๊ฒ Application ์์กด์ฑ ์ฃผ์ ์ ์์์ ์ ์๋ ค์ฃผ๋ ์ญํ ์ ํฉ๋๋ค.
@HiltAndroidApp
class MainApplication : Application() {
}
@AndroidEntryPoint
@HiltAndroidApp๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก Android ์ปดํฌ๋ํธ๋ค์ ์์กด์ฑ ์ฃผ์ ์์์ ์ ์๋ ค์ฃผ๋ ์ด๋ ธํ ์ด์ ์ ๋๋ค. ์ฌ์ฉ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ๋ค์ ์๋์ ๊ฐ์ต๋๋ค.
- Activity
- Fragment
- View
- Service
- BroadcastReceiver
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
...
}
@Inject
ํด๋น ์ด๋ ธํ ์ด์ ์ ํตํด ์์กด์ฑ์ ์ฃผ์ ํ ์ ์์ต๋๋ค.
class MyRepositoryImpl @Inject constructor(
private val myApi: MyApi
) : MyRepository {
}
์ ์ฝ๋์ ๊ฐ์ด @Inject constructor๋ฅผ ํ์ฉํ๋ฉด ์์ฑ์์์ ์์กด์ฑ์ ์ฃผ์ ๋ฐ์ ์ ์์ผ๋ฉฐ ๋ณ์์ ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ ๋ฐ๋ก ์์กด์ฑ์ ์ฃผ์ ํ ์๋ ์์ต๋๋ค.
ํ์ง๋ง ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํน์ interface๋ค์ ๊ฒฝ์ฐ Hilt์๊ฒ ์ด๋ป๊ฒ ์ธ์คํด์คํ๋ฅผ ํ์ฌ ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํด ์ค ๊ฒ์ธ์ง ์๋ ค์ฃผ์ด์ผ ํ๋๋ฐ ๊ทธ ์ญํ ์ด ๋ฐ๋ก @Module์ ๋๋ค.
@Module
Hilt์๊ฒ ์ด๋ป๊ฒ ํด๋น ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํ๋ฉด ๋๋์ง ์๋ ค์ฃผ๋ ์ญํ ๋ก ์์กด์ฑ ์ ๊ณต ๋ฐฉ๋ฒ์ผ๋ก๋ @Provides์ @Binds๊ฐ ์์ต๋๋ค.
@InstallIn
Hilt์๊ฒ ํด๋น ๋ชจ๋์ด ์ด๋ Scope์์ ์ฌ์ฉํ ์ ์๋์ง ์๋ ค์ฃผ๋ ์ญํ ์ ํฉ๋๋ค.
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
}
Hilt์ Components
๊ฐ๊ฐ์ Component๋ค์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ์ง๋ฉฐ ์๋ ํ๋ฅผ ํตํด ์ธ์ ์์ฑ~์๋ฉธ๋๋์ง ์ ์ ์์ต๋๋ค.
@ Binds
Hilt์๊ฒ ๊ฐ์ฒด๋ฅผ ์ด๋ป๊ฒ ์ธ์คํด์คํํ์ฌ ์ ๊ณตํด ์ค ๊ฒ์ธ์ง ์๋ ค์ฃผ๋ ์ด๋ ธํ ์ด์ ์ผ๋ก ํ๋ก์ ํธ์์ ์์ ํ๊ณ ์๋ ๊ฐ์ฒด์ ๋ํด ์ ๊ณตํด ์ค ๋ ์ฌ์ฉํฉ๋๋ค. (๋ง๋ interface๋ ์ถ์ class ๋ฑ)
1. ์ธํฐํ์ด์ค ์์ฑ
interface MyRepository {
suspend fun doNetworkCall() : Response<T>
}
2. ์ธํฐํ์ด์ค ๊ตฌํ
class MyRepositoryImpl @Inject constructor(
private val myApi: MyApi
) : MyRepository {
override suspend fun doNetworkCall(): Response<T> {
return myApi.doNetworkCall()
}
}
3. Binds๋ฅผ ํตํ ์ธํฐํ์ด์ค ์ ๊ณต๋ฐฉ๋ฒ์ Hilt์๊ฒ ์๋ ค์ค
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
@Binds
@Singleton
abstract fun bindMyRepository(myRepositoryImpl: MyRepositoryImpl) : MyRepository
}
4. ์์กด์ฑ ์ฃผ์
@HiltViewModel
class MyViewModel @Inject constructor(
private val repository: MyRepository
) : ViewModel(){
}
@Provides
@Binds์ ๋ง์ฐฌ๊ฐ์ง๋ก Hilt์๊ฒ ์์กด์ฑ ์ฃผ์ ๋ฐฉ๋ฒ์ ์๋ ค์ฃผ๋ ์ด๋ ธํ ์ด์ ์ด์ง๋ง, ์ฃผ๋ก ์ธ๋ถ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ์ฒด๋ฅผ ํ์๋ก ํ ๋ ๋ง์ด ์ฌ์ฉํฉ๋๋ค. ( Room , Retrofit , OkHttp ๋ฑ )
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideMyApi() : MyApi {
return Retrofit.Builder()
.baseUrl(BEACH_CONGESTION_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(MyApi::class.java)
}
}
ํด๋น ํฌ์คํ ์์๋ ๋ค๋ฃจ์ง ์๊ฒ ์ง๋ง ์ด ์ธ์๋ ๋ง์ ์ด๋ ธํ ์ด์ ๋ค์ด ์กด์ฌํฉ๋๋ค ๐คฉ
Hilt๋ ๋งค์ฐ ํธ๋ฆฌํ๊ณ ๋ค๋ฅธ DI๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋นํด ๋ฐฐ์ฐ๊ธฐ ์ฌ์ด ์ฅ์ ์ด ์๋ ๊ฒ ๊ฐ์ต๋๋ค.
์กฐ๊ธ ๋ ๊ณต๋ถํ์ฌ ์ต์ํ๊ฒ ๋ง๋ ๋ค๋ฉด ์์ฃผ ์ข์ ๋ฌด๊ธฐ๊ฐ ๋ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค.
์ด์์ผ๋ก Hilt ํฌ์คํ ์ ๋ง์น๊ฒ ์ต๋๋ค.
์ค๋๋ ์ฆ์ฝ ํ์ธ์ :)