코딩하는 일용직 노동자

Hilt, 5분 만에 정복하기 (feat. 배달 서비스 비유) 본문

안드로이드

Hilt, 5분 만에 정복하기 (feat. 배달 서비스 비유)

bacass 2025. 12. 14. 17:00

안드로이드 개발을 하다 보면 **DI(Dependency Injection, 의존성 주입)**라는 벽에 부딪힙니다. "Dagger2는 너무 어렵다", "보일러 플레이트 코드가 너무 많다"는 이야기를 들어보셨을 겁니다.

Google이 만든 Hilt는 이 어려운 DI를 아주 쉽게 만들어준 도구입니다. 오늘은 복잡한 이론 대신, **"배달 서비스"**에 비유해서 Hilt의 핵심 사용법을 딱 4단계로 정리해 보겠습니다.

💡 Hilt 핵심 개념: "자동 배달 서비스"

Hilt를 사용하는 것은 요리(객체 생성)를 직접 하지 않고, 배달(주입)시키는 것과 같습니다.

  • 나(Activity): "이거 갖다줘(@Inject)"라고 주문만 하면 됨.
  • Hilt: 주문받은 객체를 문 앞까지 알아서 배달해줌.

 

1단계: 배달 앱 켜기 (초기 설정)

Hilt를 사용하려면 가장 먼저 앱 전체에 "우리 이제 Hilt 배달 서비스 씁니다"라고 알려야 합니다. Application 클래스를 만들고 @HiltAndroidApp 어노테이션을 붙입니다.

// MyApplication.kt
import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp // 필수! Hilt 서비스를 시작하는 버튼
class MyApplication : Application()

주의: AndroidManifest.xml의 <application> 태그 내 android:name=".MyApplication" 속성 지정도 잊지 마세요!

 

2단계: 메뉴판 만들기 (객체 생성 방법 정의)

Hilt가 배달을 하려면, 그 객체를 어떻게 만드는지 알아야 합니다. 특히 Retrofit, Room 같은 라이브러리나 Interface는 Hilt가 만드는 법을 모르기 때문에 **모듈(Module)**을 통해 알려줘야 합니다.

// NetworkModule.kt
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class) // 이 메뉴는 앱이 죽을 때까지 제공됩니다 (싱글톤 스코프)
object NetworkModule {

    @Provides // 만드는 방법 제공
    @Singleton // 인스턴스 하나만 만들어서 계속 재사용
    fun provideMyService(): MyService {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .build()
            .create(MyService::class.java)
    }
}

 

3단계: 배달 받을 집 표시 (진입점 설정)

모든 곳에 배달해 주지는 않습니다. 액티비티나 프래그먼트에서 Hilt를 쓰려면 **"여기는 Hilt 배달 가능 지역입니다"**라고 문패를 달아야 합니다. 바로 **@AndroidEntryPoint**입니다.

// MainActivity.kt
import dagger.hilt.android.AndroidEntryPoint
import androidx.appcompat.app.AppCompatActivity

@AndroidEntryPoint // 필수! 여기로 배달해주세요
class MainActivity : AppCompatActivity() {
    // ...
}

 

4단계: 주문하기 (의존성 주입)

이제 준비는 끝났습니다. 변수를 선언하고 **@Inject**만 붙이면 Hilt가 알아서 객체를 채워줍니다. 직접 = MyService() 처럼 초기화할 필요가 없습니다.

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject // 주문! (Hilt가 알아서 채워줌)
    lateinit var myService: MyService 

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // myService는 이미 주입되어 있음. 바로 사용 가능!
        myService.doSomething()
    }
}

 

실전: ViewModel에 적용하기

안드로이드 개발의 꽃, ViewModel은 조금 방식이 다릅니다. 필드 주입이 아니라 생성자 주입을 사용합니다. (이게 Hilt의 표준 방식입니다.)

1. ViewModel 정의 (@HiltViewModel)

// MainViewModel.kt
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel // 나 Hilt 뷰모델이야
class MainViewModel @Inject constructor( // 생성자로 주입받음
    private val myService: MyService
) : ViewModel() {
    // ...
}

2. Activity에서 호출 (by viewModels()) 별도의 Factory를 만들 필요 없이, 아래 한 줄이면 끝납니다.

// MainActivity.kt
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    
    // Hilt가 주입한 뷰모델을 가져옴
    private val viewModel: MainViewModel by viewModels() 
}

 

Hilt, 일단 이 4단계 패턴으로 적용해 보면서 더 깊은 기능(Scope, Custom Component 등)을 익혀가시면 됩니다.