본문 바로가기
Android 개발/Hilt, Koin, DI(Dependency Injection)

HILT 에 대해서 정리해 보겠습니다. # DI Dependency Injection

by Developer88 2022. 9. 16.
반응형

오늘은 Hilt를 이용한 Dependency Injection에 대해서 정리해 보도록 하겠습니다.

Dependency Injection에 대해 경험이 없으신 분들이라면, 아래 글을 통해서 기본적인 개념에 대해서 이해해 보시면 도움이 될 것 같습니다. 특히 Dependency를 주입해준다는 말의 의미에 대해서 이해해 보아야 합니다.

>> Dependency Injection(DI)에 대해서 알아보자

이제 DI에 대해서 이해가 가신다면, HILT에 대해서 알아보도록 하겠습니다.

 

1. HILT

HILT는 Google의 Dagger를 기반으로 만든 Dependency Injection 라이브러리인데요.

공식문서에는 Hilt의 목표에 대해서 아래와 같이 정리하였는데요.

Kolin이 Kotlin에 특화된 심플한 DI라이브러리라면,

안드로이드 앱이 명시되어 있을 정도로 Android에 특화된 앱이라고 할 수 있겠습니다.

 

 

Android 공식문서에도 Hilt에 대해서 잘 설명해주고 있기때문에 많은 도움을 받을수있습니다.

다만, 주의할 점은 Android 공식문서는 최신화가 느리기 때문에,

아직 Alpha단계로 변화가 많은 Hilt의 라이브러리에 대해서는 공식문서에서 확인이 필요합니다.

간혹, 기존에 사용하던 Annotation이 사용할 수 없는 경우도 있는데요.

공식페이지의 문서를 통해 변경사항을 확인해 보시는 것이 좋습니다.

 

2. Library설정

현재는 2.51.1 버전을 사용하도록 되어 있습니다.

먼저, 앱레벨의 build.gradle에서 dependencies를 아래와 같이 추가해 줍니다.

implementation과 annotation을 위해서 사용할 katp를 추가해 줍니다.

다른 라이브러리 설정과 다르게, 한가지 추가해 줄 것은 correctErrorTypes를 true로 설정해 주는 것 입니다.

 

dependencies {
  def hilt_version = "2.51.1"
    implementation "com.google.dagger:hilt-android:$hilt_version"
    kapt "com.google.dagger:hilt-compiler:$hilt_version"
    kapt 'androidx.hilt:hilt-compiler:1.0.0'

    implementation 'androidx.hilt:hilt-navigation-compose:1.0.0'
    // jetpack compose를 사용하는 경우
}

kapt {
    correctErrorTypes true
}

 

 

여기서 끝나지 않구요. hilt의 plugin을 설치해 주어야 합니다.

먼저 위에서 작성한 앱레벨의 build.gradle의 위쪽에 보면 plugin에 관한 부분이 있는데요.

아래와 같이 추가해 줍니다.

대부분 com.android.application은 이미 추가가 되어있을테니,

hilt부분 한줄만 추가해주면 되겟지요.

 

apply plugin: 'com.android.application'
apply plugin: 'com.google.dagger.hilt.android'

 

아래와 같이 plugins 블록안에 추가해도 동일합니다.

 

plugins {
    id 'com.android.application'
    id 'dagger.hilt.android.plugin'
}

 

여기서 끝이 아니구요. 

다음으로 Project레벨의 build.gradle도 열어줍니다.

buildscript 블록을 아래와 같이 구성해 주기 위해서 입니다.

저의 경우는 mavenCetral()은 이미 추가되어 있어서, classpath만 추가해 주었습니다.

 

buildscript {
  repositories {  
    mavenCentral()
  }
  dependencies {
    classpath 'com.google.dagger:hilt-android-gradle-plugin:2.43.2'
  }
}

 

 

 

 

3. Application Class 와 SingletonComponent

Hilt를 사용하기 위해서는 ApplicationClass가 필요합니다.

Hilt라이브러리가,

ApplicationClass와 ApplicationContext에 접근해서,

뒤에서 많은 일들을 해야 하기 때문입니다.

 

보통 MyApplicatoin 같은 이름을 많이 사용하는데요.

클래스이름 위에, "@HiltAndroidApp" 이라는,

Annotation을 추가해 주어야 합니다.

 

 @HiltAndroidApp
 class MyApplication : Application() { ... }

 

이렇게 annotation을 추가해주면,

HiltAndroidApp Annotation에 의해,

Singleton Component가 생성됩니다.

이것은 앱이 살아있는 동안 Dependency를 제공하는,

애플리케이션 레벨의 Component입니다.

 

참고로, Application클래스를 생성한 뒤,

AndroidManifest파일의 application태그에,

아래와 같이 name을 설정해 주어야 합니다.

 

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

 

 

이제 Hilt가 Dependency를 제공할 수 있도록 준비작업이 되었습니다.

4. 각 클래스 Component생성

위에서 Application클래스에 annotaiton을 붙여,

application레벨의 컴포넌트를 생성하였습니다.

 

Hilt는 컴포넌트들을 이용해,

필요한 Dependency를 클래스에 제공하는데요.

 

Hilt가 Dependency를 주입해 줄 수 있는 클래스의 종류는 다음과 같은 것들이 있는데요.

(위에서 @HiltAndroidApp으로 추가한 ApplicationClass는 제외하였습니다.)

아래 클래스들에 "@AndroidEntryPoint" annotation을 붙여주면

Hilt가 해당 클래스에,

Dependency를 제공해 줄 수 있는 Component를 생성해 줍니다.

 

  • Activity
    • ComonentAcitivty를 상속받는 Activity만 지원한다.
      • AppCompatActivity가 대표적인 예
  • Fragment
    • androidx.Fragment를 상속받는 Fragment클래스에만 dependency주입가능
  • View
  • Service
  • BroadcastReceiver

 

예를 들면 아래와 같이 Annotation을 붙여서 컴포넌트를 만들고 Dependency를 주입받을 수 있도록 하는 것 이지요.

정말 심플하지요? 저희는 annotation만 적절하게 붙여주면 됩니다.

 

 

 

참고로 생성된 Component들은 아래와 같은 hierarchy를 갖습니다.

ApplicationClass에서 생성된 SingletonComponet가 가장 상위에 있겠지요.

각 Component들은 그 부모로부터 Dependency를 받을 수 있습니다.

 

 

 

해당 Component들은 아래와 같은 함수 호출시점에 생성되고, Destroy되는데요.

참고로 아래 표는 시간이 조금 흐른 후의 표인데요.

ApplicationComponent는 SingletonComponent로 대체되었으므로 참고해주세요.

 

 

5. Injection

Hilt는 Dependency Graph를 생성해,

필요한 곳에 Dependency(의존성)를 주입해주는 라이브러리입니다.

위에서 말한 주입을 영어로 Injection이라고 합니다.

 

어떤 곳에서 Depedency가 필요하다고 Annotation이 붙어있다면,

해당하는 객체를 어떻게 생성하는지 Hilt가 알고있어야 합니다.

 

객체를 생성하는 건 클래스의 역할인데요.

우리가 원하는 객체를 생성할 수 있는 클래스에,

"@Inject" Annotation을 붙여서,

hilt에게 어떤 클래스를 이용해야 생성되는지 알려주어야 합니다.

그럼, hilt가 Dependency Graph를 연결해서,

필요할 때 제공해 주는 것 이지요.

 

글이 길었지만,

핵심은 hilt가 알 수 있도록,

"@inject" annotation을 다음 2곳에 붙여주는 것 입니다.

  • Hilt가 Dependency를 제공해서 생성할 객체의 클래스에 붙여주기
  • Dependency를 주입받을 객체에 붙여주기

 

 

6. 2가지 injection

위에서 "@Inject"를 붙여줌으로서, dependency를 주입(injection)할 수 있다고 했는데요.

Injection은 아래 2가지 방법으로 나누어 집니다.

  • Field Injection: @Inject 어노테이션을 사용하여 클래스의 필드에 직접 의존성을 주입
    • 주로 @AndroidEntryPoint가 붙은 안드로이드 컴포넌트(Activity, Fragment 등)에서 사용
  • Constructor Injection: 클래스의 생성자 앞에 @Inject 어노테이션을 붙여 의존성 주입
    • ex) class TestClass @Inject constructor() { ... }

Constructor와 Field Injection이 어떻게 다른지 보도록 하겠습니다.

 

5-1. 간단한 형태의 Field Injection

AnalyticsAdapter객체를 생성하는 아래 클래스를 보도록 하겠습니다.

이 객체가 Hilt에 의해 주입받을 수 있는 객체의 클래스라는 것을 알려주기 위해서 생성자에 "@Inject" annotation을 붙여주었습니다.

 

class AnalyticsAdapter
@Inject
constructor() { 

}

 

이 클래스는 Component 들에서 사용이 가능할텐데요.

대표적으로 @AndroidEntryPoint Annotation을 붙인 Activity에서 사용이 가능하겠지요.

 

아래와 같이, "@Inject" annotation을 붙여서 원하는 field에 객체를 주입받을 수 있게 됩니다.

해당 클래스에서 생성하지 않고도 객체를 주입받아 사용하는 것 이지요.

위에서 선언한 방식이 생성자 Injectoin이라면, 이러한 방식은 Field Injection입니다.

 

@AndroidEntryPoint
class TestActivity : AppCompatActivity() {

  @Inject 
   lateinit var analytics: AnalyticsAdapter
  ...
}

 

 

 

주의할 점은, Hilt에 의해 주입받은 변수 객체는 private할 수 없다는 것입니다.

만약 private filed로 선언하면, compilation error가 납니다.

 

5-2. Constructor Injection

의존성이 있는 두가지 클래스를 보도록 할 텐데요.

ATypeClass와 BTypeClass가 있다고 가정해 보겠습니다.

 

BTypeClass는 "@Inject" Annotation을 붙어서 주입될 객체라고 표시가 되었구요.

ATypeClass도 마찬가지지만, 생성자에서 BTypeClass의 객체를 주입받고 있는 데요.

Constrouctor Injection이 사용되는 것 입니다.

 

Constructor Injection을 사용함으로서,

생성시에 어떤 클래스의 객체가 필요한지 Hilt가 알수 있고,

개발자도 알 수 있게 되었습니다.

 

class ATypeClass
@Inject
constructor(private val bTypeClass: BTypeClass) {
    fun doBtypeTest(): String {
        return bTypeClass.test()
    }
}

class BTypeClass
@Inject
constructor() {
  fun test(): String {
    return "test is done"
  }

}

 

위의 두 클래스를 이용해서, 아래와 같이 field injection으로 객체를 주입받아, 사용할 수 있습니다.

 

@AndroidEntryPoint
class TestActivity : AppCompatActivity() {

  @Inject 
   lateinit var aType: ATypeClass

   overide fun onCreate(savedInstanceState: Bundle?){
        aType.doBtypeTest()
  }

}

 

 

그런데, Construction Injection을 사용할 수 없는 경우들이 존재하는데요.

아래에서 보도록 하겠습니다.

6. Constructor Injection 예외

6-1. Interface를 Construcotr Injection에 사용하는 것은 금지되어 있음

아래와 같이 interface가 있다고 가정해 보겠습니다.

 

interface AInterface {
  fun showString(): String
}

 

위의 Ainterface를 implement하는,

ClassA와 ClassB가 존재한다고 가정해 보겠습니다.

 

이들은 각각 AInterface를 implement할 것인데요.

문제는,

interface를 inject하는 Constructor Injection이 사용되었기 때문에,

정상적으로 Inject되지 않고 에러가 나게 됩니다.

 

interface나 interface를 implement하는 객체를 inject할 수 없는 것 이지요.

이것은 Hilt가 interface가 implement된 타입의 객체를,

어떻게 생성해야 하는지 알 수 없기 때문입니다.

 

class ClassA
@Inject
constructor(private  val bTypeVal: AInterface){
 fun doTestA(): String {
   return bTypeVal.doTestB()
 }
}

class ClassB
@Inject
constructor(): AInterface {
  override fun showString(): String {
    return "get Go!"
  }
}

interface AInterface {
    fun showString(): String
}

 

 

6-2. 외부 라이브러리 클래스의 객체를 Inject하는 것은 금지됨

retrofit같은 라이브러리의 객체를 Construcotr Injection하는 것은 금지되어 있습니다.

자신이 만든 클래스가 아닌 곳에 @Inject를 annotation에 추가할 수도 없기 때문에,

마음대로 사용하는 것은 불가능하지요.

HILT가 이 객체를 어떻게 만들어야 할지 모르기 때문입니다.

 

그럼 위의 두가지 케이스를 해결하기 위해서는 어떤 방법을 써야할까요?

아래에서 알아보도록 하겠습니다.

 

7. Hilt Modules

"@Inject 붙여서 생성하는 곳과 사용하는 곳에 해주면 되는 것 아니야?"
라고 생각했었는데요.

 

위의 6에서 본 것처럼,

interface나 외부 라이브러리의 객체처럼, 

Hilt가 어떻게 객체를 생성해야 할지 모르는 경우에는,

@Inject를 사용할 수 없었습니다.

 

이럴 때는,

Module을 이용해,

Hilt에게 원하는 객체를 생성하는 방법을 알려주어야 합니다.

 

Module을 사용하는 방법은 다음의 2가지가 있습니다.

  • @Provides Annotation: 객체 생성 로직을 직접 작성할 수 있음
    • 외부 라이브러리나 빌더 패턴을 사용하는 객체에 주로 사용
  • @Binds Annotation: 인터페이스와 그 구현체를 바인딩할 때 사용
    • 추상 함수로 선언하며, 파라미터로 구현체를 받고 리턴 타입으로 인터페이스를 지정

 

보통은 임의의 Module클래스를 생성한 후,

이곳에 Module클래스들을 생성해 사용하게 됩니다.

 

7-1. Provides

Provides annotation을 붙여서 hilt에게 객체 생성방법을 알려주는 과정은,

아래와 같습니다.

  1. Module클래스 생성과 @Module annotation 붙이기
  2. @InstallIn annotation 붙이기
  3. @Provides annotation 을 객체 생성하는 함수에 붙이기

그럼 실제로 위의 과정들을 적용한 코드를 보겠습니다.

 

먼저, Module을 사용하기 전에,

@Inject를 사용할 수 없는 Interface를 implement한,

ClassA와 ClassB를 보겠습니다.

 

ClassB의 생성자에 String타입의 cDependency가 인자로 들어갑니다.

@Inject를 사용하였지만, hilt는 이 객체를 어떻게 만드는지 모릅니다.

Module이 필요하겠지요.

 

class ClassA
@Inject
constructor(private  val bTypeVal: AInterface){
 fun doTestA(): String {
   return bTypeVal.doTestB()
 }
}

class ClassB
@Inject
constructor(private val cDependency: String): AInterface {
  override fun doTestB(): String {
    return "get Go ${cDependency}!"
  }
}


interface AInterface {
    fun showString(): String
}

 

이제 힐트가 어떻게 객체를 생성하는지 알 수 있도록,

Module클래스를 생성한 코드를 보겠습니다.

 

@Module
@InstallIn(ActivityComponent::class)
class AModule {

   @Provides
   fun provideCString(): String {
      return "c String"
   }

  
    @Provides
    fun testProvides(cString: String): AInterface {
       return ClassB(cString)
    }
}

 

가장 먼저 한 것은 class위에 "@Module" Annotation을 붙여주는 것 입니다.

그래야 Hilt가 여기가 Module이 있는 곳임을 알 수 있겠지요.

 

다음으로 "@InstallIn" Annotation을 붙여줍니다.

Hilt에게 이 Class의 객체가 어디에서 사용되는지를 알려주는 부분인데요.

예를 들어, @InstallIn(ActivityComponent::class)는,

해당 모듈이 acitivity에서 사용가능하다고 선언하다는 의미입니다.

 

Activity가 아닌 다른 Component라면, 해당 Component의 이름을 넣어주면 됩니다.

(Component들의 이름은 위의 글4의 Component에 대한 설명을 참조해주세요.)

 

이제 Module Class내부에,

Provides함수들을 넣어줍니다.

 

위 코드는 두가지의존성을 제공합니다.

하나는 cDependency라는 String객체이구요.

또 하나는 AInterface타입의 객체입니다.

 

Hilt는 둘 다 어떻게 만드는지 모르므로,

해당 객체를 생성하는 함수에,

Provides Annotation을 붙여주었습니다.

 

7-2. 외부라이브러리에 @Provides 사용하기

Room DB, Retrofit이나 Gson과 같은 외부라이브러리객체의 경우

Provide를 이용해서 Dependency를 제공할 수 있습니다.

 

아래 코드는 Room데이터베이스, Repostitory클래스의 객체생성방법, Retrofit, Gson등의 객체를 생성하는 방법들을 Hilt에게 알려주고 있습니다. 경우에 따라서 객체 생성시, Application Context를 제공해 주어야 하는데요.

아래와 같이 인자에 application을 넣어주면 Hilt가 알아서 넣어줍니다.

 

@Module
@InstallIn(SingletonComponent::class)
object TestModule {
    @Singleton
    @Provides
    fun provideReceiptDatabase(application: Application): ReceiptDatabase {
        return Room.databaseBuilder(
            application,
            ReceiptDatabase::class.java,
            "receipt_db"
        )
        .fallbackToDestructiveMigration() //should be removed when going out as a product
        .build()
    }

    @Singleton
    @Provides
    fun provideReceiptRepository(receiptDatabase: ReceiptDatabase): ReceiptRepository {
        return ReceiptRepositoryImpl(receiptDatabase.dao)
    }


    @Singleton
    @Provides
    fun provideAService(): AService {
       return Retrofit.Builder()
                 .baseUrl("https://a.com")
                 .build().create(AService::class.java) 
    }

  @Singleton
  @Provides
   fun provideGson(): Gson {
      return Gson()
   }
}

 

 

7-3. 같은 타입의 객체에 대한 Dependency

같은 타입의 객체를 여러개 주입할 경우,

어떤 클래스의 Dependency를 Inject 해야할지 Hilt가 알수 없습니다.

 

특히 Interface를 implement한 경우가 그렇습니다.

어느 클래스가 interface를 implement하였는지 hilt는 모르니까요.

 

이럴때는 아래와 같이 "Qualifier" 구분을 해주면 되는데요.

"@Qualifier @Retention(AnnotationRetention.BINARY)" Annotation을 붙여,

구분할 Identifier라고 Hilt에 알려주구요.

키워드로 annotation class를 붙인다음 이름을 정해줍니다.

아래에서는 TestType1과 TestType2를 사용하였습니다.

이제 Hilt는 이 Qualifier를 따라서 Dependency를 주입해 줍니다.

 

@Module
@InstallIn(SingletonComponent::class)
object TestModule {

   @Qualifier
   @Retention(AnnotationRetention.BINARY)
    annotation class TestType1

   @Qualifier
   @Retention(AnnotationRetention.BINARY)
    annotation class TestType2
  
    @TestType1
    @Provides
    fun testProvides1(): AInterface {
       return ClassB()
    }

   @TestType2
   @Provides
    fun testProvides2(): AInterface {
       return ClassB()
    }

}

 

 

위에서 만든 Qualifier를 사용해 보겠습니다.

ClassA는 AInterface타입으로 객체를 두개 받습니다.

Hilt입장에서는 어떤 객체를 연결시켜주어야 하는지 모르게되는데요.

생성자의 인자들 앞에 보시면 "@TestType1"과 "@TestType2"를 붙여주었습니다.

각각 다른 identifier를 붙여주어서 구분해 준 것입니다.

 

class ClassA
@Inject
constructor(
    @TestType1 private  val bTypeVal1: AInterface,
    @TestType2 private  val bTypeVal2: AInterface,
){
    fun doTest1(): String {
        return bTypeVal.doTestB()
     }
    fun doTest2(): String {
         return bTypeVal2.doTestC()
     }
}

class ClassB
@Inject
constructor(): AInterface {
    override fun doTestB(): String {
         return "First Implementation"
    }
}

class ClassC
@Inject
constructor(p): AInterface {
  override fun doTestC(): String {
    return "Second implementation"
  I
}


interface AInterface {
    fun showString(): String
}

 

위와 같이해주면, Hilt가 어떤 Dependency를 어디에 연결해서 주입해야되는지를 알게 되는 것 이지요.

Provide에 대해서는 정리해 보았는데요. Binds방식에 대해서도 알아보도록 하겠습니다.

 

7-3. Binds

이번에는 Binds방식으로는 어떻게 하는지 보도록 하겠습니다.

참고로 Binds방식은 외부라이브러리에는 사용할 수 없습니다.

interface타입의 객체를 어떻게 만드는지 Hilt에게 알려주기 위한 용도로 사용하는 것 이지요.

 

먼저 ClassA가 Constructor Injection을 사용하고 있고,

아래의 AInterface를 implement하고 있기 때문에 compile에러가 난다고 했었는데요.

(Hilt는 Interface가 implement된 타입이 Constructor Injection된 경우 어떻게 생성해야 하는지 모른다고 했었지요.)

 

class ClassA
@Inject
constructor(private  val bTypeVal: AInterface){
 fun doTestA(): String {
   return bTypeVal.doTestB()
 }
}

class ClassB
@Inject
constructor(): AInterface {
  override fun showString(): String {
    return "get Go!"
  }
}

interface AInterface {
    fun showString(): String
}

 

Provides와 마찬가지로 "@Module" Annotation을 붙여주구요.

abstract class를 만든다음, abstract 함수를 정의해 주면 됩니다.

Provide때와 마찬가지로 "@Binds" Annotation을 붙여주는데요.

 

그리고 필수는 아니지만, AcitivityScope를 의미하는 @ActivityScoped를 붙여서 Scope까지 정의해 주었습니다.

Injecting한 Dependency를 언제까지 사용할 것인지 정의하는 것 이지요.

다만 주의할 점은, Module에서 정의한 InstallIn의 Component의 Scope의 범위를 여기서 정의한 Scope가 벗어나면 않됩니다.

(Scope에 관한 부분은 7번 Scope를 참조해주세요)

 

아래와 같이 해주면, 이제 Hilt가 AInterface타입의 객체는 어떻게 생성하여야 하는지 알게되는 것 이지요.

AInterface타입이지만, classB에서 객체를 생성해야 한다고 알려주는 것이지요.

아래에서는 ClassB타입의 객체가 되겠지요.

 

@Module
@InstallIn(ActivityComponent::class)
abstract class AModule {
      @ActivityScoped
      @Binds
      abstract fun bindInterfaceDependency(testClassB: ClassB): AInterface
}

 

위와 같이 abstract class타입의 Module을 생성해서 함수를 만들어 넣어주면 되는 것 인데요.

핵심은 interface처럼 어디서 객체를 생성해야 할지 모르는 Hilt에게, 어떤 클래스로부터 가져온 객체라고 알려주는 것입니다.

다만 위에서 언급한데로, 이 방법은 Provide와는 달리 외부 라이브러리 객체에 대해서는 동작하지는 않으므로 사용에 주의가 필요합니다.

 

8. Scope

Scope에 대해서도 알아둘 필요가 있는데요.

Hilt에서는 각 Class들에 대응하는 Component와 Scope를 같이 유지함으로써,

매번 객체를 주입할 때마다 새로운 객체를 생성하는 것이 아닌, 해당 Scope내에서 사용할 수 있도록 하고 있습니다.

Activity보다 오래 살아남는 ViewModel의 경우는

ActivityRetainedComponent와 ActivityRetainedScope를 가지게 해야합니다.

 

참고로 아래의 ApplicationComponent는 SingletonComponent로 변경되었습니다.

 

 

Class를 생성하면서 Scope를 위의 표에 있는 것으로 설정해 주면,

해당 Scope의 주기를 따라가게되겠지요.

해당 객체가 Fragment가 살아있는 동안에만 쓰인다면,

"@FragmentScoped"로 Scope를 Annotation에 명시해주면 더욱 좋겠지요.

 

참고로, Activity에서 주입될 객체를 생성하는 클래스에 @FragmentScoped를 붙인다면 당연하게도 에러가 나게 되겠지요.

 

그리고, Scope에 대해서 아무것도 Annotation을 붙이지 않는다면 어떻게 될까요?

해당 Class는 생성시마다 계속 새로 생성되게 되겠지요.

 

9. Hilt와 ViewModel

9-1. ViewModel 작성

Koin도 ViewModel에서 Inject하기 쉬운 방법을 제공했었는데요.

Hilt도 마찬가지입니다. Annotation만 붙여주면 되는데요.

다만 그전에 라이브러리를 implement 해 주어야 합니다.

 

아래의 라이브러리를 implementation해 주어야 합니다.

fragment-ktx는 관련이 없어보이지만 필요하니 잊지말고 추가해주어야 합니다.

 

implementation "androidx.fragment:fragment-ktx:1.8.5"

 

라이브러리가 업데이트 되면서 "@HiltViewModel" 로 Annotation Name이 바뀌었습니다.

savedStateHandle도 필요한 경우에 넣으면, Hilt가 주입해 줍니다.

 

 

 

9-2. Activity나 Fragment 에서 객체주입

위와 같이 ViewModel클래스를 넣어 주었다면,

@AndroidEntryPoint Annotation이 붙은 Activity나 Fragment에서 아래와 같이 바로 사용이 가능합니다.

만약 viewModels()가 활성화되지 않았다면, 위에서 필요로하는 라이브러리 중 하나가 빠지지 않았는지 확인해 보아야 합니다.

@Inject Annotation은 필요하지 않습니다.

 

 

9-3. 인자에 viewModel 주입

Jetpack Compose시대에 다른 파일에서 작성하는 Compose에서 viewModel을 호출해서 사용하는 경우들이 생기는데요.

아래와 같이 간단하게 Hilt가 ViewModel을 주입하게 할 수 있습니다.

 

 

10. ApplicationContext 가 필요할 때

객체 생성시 ApplicationContext가 필요할 때가 있는데요.

예를 들어서 아래와 같이 provide를 이용해서, interface를 생성하는 방법을 Hilt에 알려줄려고 할 때,

@ApplicationContext 를 Annotation으로 사용해주면 Hilt가 알아서 생성해주므로, 바로 사용이 가능합니다.

 

@Module
@InstallIn(SingletonComponent::class)
class TestModule {
    @Singleton
    @Provides
    fun provideTest(@ApplicationContext appContext: Context): Test {
        return Test(appContext)
    }
}

 

11. 정리

지금까지 DI라이브러리인 HILT에 대해서 정리해 보았습니다.

아직 정식버전의 라이브러리가 나오지는 않았는데요.

계속 개선될 것으로 보이구요.

이글에서 변경사항은 계속 업데이트하도록 하겠습니다.

 

728x90

댓글