Android (안드로이드)

[Android] Hilt / 힐트 / 예제 / 의존성 주입 라이브러리

Oscar:) 2024. 2. 25. 16:32

 

 

지난 2편의 의존성 주입 포스팅에 이어

이번 포스팅에서는 Hilt 라이브러리에 대해 알아보자.

 

 

 


 

 

Hilt

 

 

의존성 주입 목적 JetPack의 권장 라이브러리이며

Dagger를 기반으로 빌드되었다.

 

Dagger와 마찬가지로 Annotation Processing을 사용한다.

 

 

 

✅ Dagger의 단점 부각

 

Dagger는 초기 DI 환경을 구축하는 비용이 비효율적이라는 의견이 많았다.

Hilt를 사용하면 Dagger 관련 인프라를 간소화할 수 있다.

 

이는 기본적으로 Component를 제공해주기 때문이라고 볼 수 있다.

Hilt의 내장 Component 관련해서는 예제를 따라가며 알아보자.

 

 

지난 Dagger 포스팅에서도 언급했지만,

공식 문서에서조차 Dagger가 아닌 Hilt 사용을 권장하고 있다.

 

 

 


 

사용해보자

 

 

✅ 의존성 추가

 

build.gradle(모듈 수준)에 다음 의존성을 추가해준다.

plugins {
    id("com.google.dagger.hilt.android")
}

dependencies {
    implementation("com.google.dagger:hilt-android:2.50")
    annotationProcessor("com.google.dagger:hilt-android-compiler:2.50")
}

 

 

 

코틀린의 경우 다음과 같이 추가한다.

plugins {
    id("com.google.dagger.hilt.android")
    id("kotlin-kapt")
}

dependencies {
    implementation("com.google.dagger:hilt-android:2.50")
    kapt("com.google.dagger:hilt-android-compiler:2.50")
}

 

 


 

✅ Application 클래스 생성

 

 

Hilt를 사용하는 앱에는 Application 클래스 포함이 강제된다.

 

@HiltAndroidApp 어노테이션을 지정해야 하기 때문이다.

이 어노테이션으로 의존성 주입의 시작점이 지정된다고 볼 수 있다.

 

*Application Class
App 내 모든 컴포넌트에서 공유할 수 있는 전역 클래스이며
모든 컴포넌트 중 제일 먼저 인스턴스화 된다.
android.app.Application 클래스를 상속하여 사용한다.

 

 

 

HiltExampleApplication.java

@HiltAndroidApp
public class HiltExampleApplication extends Application {}

 

해당 클래스에는 별다른 코드를 작성할 필요가 없다.

 

Application 클래스를 상속하고,

@HiltAndroidApp 어노테이션만 작성해주면 된다.

 

 

 

 

▶ Manifest 파일 수정

 

Manifest 파일 내 application 태그에 위에서 생성한

Application 클래스를 추가해줘야 한다.

 

아래와 같이 android:name 속성만 추가해주면 된다.

 

 

AndroidManifest.xml

<application
    android:name=".HiltExampleApplication"
    ...
</application>

 

 


 

✅ 의존성이 될 클래스 세팅

 

Dagger 예제와 동일한 부분이다.

 

Car · Engine 클래스를 의존성으로 사용할 것이기에

해당 클래스를 간단히 만들어준다.

 

 

Car.java & Engine.java

public class Car {

    Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    void start() {
        engine.start();
    }

}

public class Engine {

    void start() {
        System.out.print("부르릉~");
    }

}

 

 


 

 

✅ Module 생성

 

CarModule.java

@Module
@InstallIn(ActivityComponent.class)
public class CarModule {

    @Provides
    @ActivityScoped
    Car provideCar(Engine engine) {
        return new Car(engine);
    }

    @Provides
    @ActivityScoped
    Engine provideEngine() {
        return new Engine();
    }

}

 

Dagger 예제의 Module과 크게 다른 점은 없다.

@InstallIn, @ActivityScoped 어노테이션만 유심히 보자.

 

 

 

● Hilt에서 모든 Module은 반드시 Component에 지정되어야 한다.

@InstallIn 어노테이션을 사용하여 Module을 Component에 install 해준다.

Hilt에서 제공하는 내장 Component의 종류는 다음과 같다.

- SingletonComponent
- ActivityComponent
- FragmentComponent
- ServiceComponent
- ViewComponent


Component는 각자의 생명주기를 가지고 있으며,
해당 Module도 이 생명주기를 따라간다.

 

 

 

● 또한 각 Component는 Scope의 개념이 동반된다.

 

기본적으로 Hilt는 의존성 결합이 요청될 때마다 해당 객체를 생성하는데,
특정 의존성에 대한 Scope를 지정하면
Component의 생명주기가 파괴될 때까지는 동일한 객체를 공유한다.

 

SingletonComponent → @Singleton
ActivityComponent → @ActivityScoped
FragmentComponent → @FragmentScoped

 

 

 

이번 예제에서는 MainActivity에 의존성을 주입할 것이므로

ActivityComponent를 지정해주고, @InstallIn(ActivityComponent.class)

제공할 의존성에는 @Provides와 함께 @ActivityScoped를 사용했다.

 

 


 

 

✅ MainActivity에서 Inject

 

 

MainActivity.java

@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {

    @Inject
    Car car;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        car.start();

    }
    
}

 

● @AndroidEntryPoint 어노테이션이 지정된 모든 클래스에 의존성을 제공할 수 있다.

 

해당 어노테이션은 Application / Activity / Fragment / Service / ViewModel 등

웬만한 클래스에 지정할 수 있다.

 

 

Car 객체에 @Inject 어노테이션으로 의존성을 주입할 대상을 지정했다.

 

Car 객체를 선언만 했고, 초기화 해주는 부분은 없지만

의존성을 주입 받았기에 사용할 수 있다.

 

 


 

✅ 실행

 

 

 

Engine 클래스의 start() 메서드 로그가 잘 찍혔다.

 

 

 


 

정리

 

 

▶ Application 단위의 클래스 생성 후 @HiltAndroidApp 어노테이션 작성

 

▶ Manifest 파일의 application 태그에 name 속성 추가

 

▶ 주입할 의존성 생성 & Module 생성

 

▶ Module에 @Module 어노테이션과 함께 @InstallIn 어노테이션으로 내장 컴포넌트 지정

 

▶ 주입할 의존성에 @Provides, @..Scope 어노테이션 작성

 

▶ 의존성 주입 받을 곳에 @AndroidEntryPoint 어노테이션 작성

 

▶ 의존성 주입 받을 객체에 @Inject 어노테이션 작성

 

 

Dagger에 비해 훨씬 간소화되었는데도 이렇게 쓰고 보니 뭐가 많아 보인다..

 

 


 

 

✅ Dagger와 Hilt 한 눈에 비교하기

 

 

● Dagger

 

 

● Hilt

 

 

Hilt는 내장 Component를 사용하기 때문에 Component를 직접 만들어줄 필요가 없다.

 

어노테이션만 잘 붙여주면 되기에 초기 구축 비용이 훨씬 간소화된다.

 

 

 


 

 

 

이번 포스팅에서는 Hilt에 대해 알아보았다.

 

세미 프로젝트를 더 한다면 실제로도 사용해보고 싶다.